aeson 0.9.0.1 → 0.10.0.0
raw patch · 64 files changed
+8541/−1641 lines, 64 filesdep ~QuickCheckdep ~attoparsecdep ~mtlPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: QuickCheck, attoparsec, mtl, template-haskell, time
API changes (from Hackage documentation)
- Data.Aeson.Encode: encodeToByteStringBuilder :: Value -> Builder
- Data.Aeson.Generic: decode :: Data a => ByteString -> Maybe a
- Data.Aeson.Generic: decode' :: Data a => ByteString -> Maybe a
- Data.Aeson.Generic: encode :: Data a => a -> ByteString
- Data.Aeson.Generic: fromJSON :: Data a => Value -> Result a
- Data.Aeson.Generic: toJSON :: Data a => a -> Value
+ Data.Aeson: class KeyValue kv
+ Data.Aeson: data Encoding
+ Data.Aeson: data Series
+ Data.Aeson: defaultOptions :: Options
+ Data.Aeson: foldable :: (Foldable t, ToJSON a) => t a -> Encoding
+ Data.Aeson: fromEncoding :: Encoding -> Builder
+ Data.Aeson: gToEncoding :: GToJSON f => Options -> f a -> Encoding
+ Data.Aeson: genericToEncoding :: (Generic a, GToJSON (Rep a)) => Options -> a -> Encoding
+ Data.Aeson: pairs :: Series -> Encoding
+ Data.Aeson: toEncoding :: ToJSON a => a -> Encoding
+ Data.Aeson.Internal: IError :: JSONPath -> String -> IResult a
+ Data.Aeson.Internal: ISuccess :: a -> IResult a
+ Data.Aeson.Internal: data IResult a
+ Data.Aeson.Internal: data JSONPathElement
+ Data.Aeson.Internal: formatError :: JSONPath -> String -> String
+ Data.Aeson.Internal: ifromJSON :: FromJSON a => Value -> IResult a
+ Data.Aeson.Internal: iparse :: (a -> Parser b) -> a -> IResult b
+ Data.Aeson.Internal: type JSONPath = [JSONPathElement]
+ Data.Aeson.Internal.Time: TOD :: {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int64 -> TimeOfDay64
+ Data.Aeson.Internal.Time: data TimeOfDay64
+ Data.Aeson.Internal.Time: diffTimeOfDay64 :: DiffTime -> TimeOfDay64
+ Data.Aeson.Internal.Time: fromPico :: Pico -> Integer
+ Data.Aeson.Internal.Time: toPico :: Integer -> Pico
+ Data.Aeson.Internal.Time: toTimeOfDay64 :: TimeOfDay -> TimeOfDay64
+ Data.Aeson.TH: mkToEncoding :: Options -> Name -> Q Exp
+ Data.Aeson.TH: unwrapUnaryRecords :: Options -> Bool
+ Data.Aeson.Types: camelTo2 :: Char -> String -> String
+ Data.Aeson.Types: class KeyValue kv
+ Data.Aeson.Types: data Encoding
+ Data.Aeson.Types: data Series
+ Data.Aeson.Types: foldable :: (Foldable t, ToJSON a) => t a -> Encoding
+ Data.Aeson.Types: fromEncoding :: Encoding -> Builder
+ Data.Aeson.Types: gToEncoding :: GToJSON f => Options -> f a -> Encoding
+ Data.Aeson.Types: genericToEncoding :: (Generic a, GToJSON (Rep a)) => Options -> a -> Encoding
+ Data.Aeson.Types: pairs :: Series -> Encoding
+ Data.Aeson.Types: toEncoding :: ToJSON a => a -> Encoding
+ Data.Aeson.Types: unwrapUnaryRecords :: Options -> Bool
- Data.Aeson: (.=) :: ToJSON a => Text -> a -> Pair
+ Data.Aeson: (.=) :: (KeyValue kv, ToJSON v) => Text -> v -> kv
- Data.Aeson: class ToJSON a where toJSON = genericToJSON defaultOptions
+ Data.Aeson: class ToJSON a where toJSON = genericToJSON defaultOptions toEncoding = Encoding . encodeToBuilder . toJSON
- Data.Aeson.TH: Options :: (String -> String) -> (String -> String) -> Bool -> Bool -> SumEncoding -> Options
+ Data.Aeson.TH: Options :: (String -> String) -> (String -> String) -> Bool -> Bool -> SumEncoding -> Bool -> Options
- Data.Aeson.Types: (.=) :: ToJSON a => Text -> a -> Pair
+ Data.Aeson.Types: (.=) :: (KeyValue kv, ToJSON v) => Text -> v -> kv
- Data.Aeson.Types: Options :: (String -> String) -> (String -> String) -> Bool -> Bool -> SumEncoding -> Options
+ Data.Aeson.Types: Options :: (String -> String) -> (String -> String) -> Bool -> Bool -> SumEncoding -> Bool -> Options
- Data.Aeson.Types: class ToJSON a where toJSON = genericToJSON defaultOptions
+ Data.Aeson.Types: class ToJSON a where toJSON = genericToJSON defaultOptions toEncoding = Encoding . encodeToBuilder . toJSON
Files
- Data/Aeson.hs +143/−100
- Data/Aeson/Encode.hs +8/−11
- Data/Aeson/Encode/Builder.hs +254/−0
- Data/Aeson/Encode/ByteString.hs +0/−123
- Data/Aeson/Encode/Functions.hs +53/−0
- Data/Aeson/Functions.hs +1/−1
- Data/Aeson/Generic.hs +0/−368
- Data/Aeson/Internal.hs +25/−0
- Data/Aeson/Internal/Time.hs +57/−0
- Data/Aeson/Parser.hs +1/−1
- Data/Aeson/Parser/Internal.hs +81/−49
- Data/Aeson/Parser/Time.hs +151/−0
- Data/Aeson/TH.hs +443/−90
- Data/Aeson/Types.hs +11/−11
- Data/Aeson/Types/Class.hs +150/−73
- Data/Aeson/Types/Generic.hs +231/−70
- Data/Aeson/Types/Instances.hs +625/−228
- Data/Aeson/Types/Internal.hs +234/−26
- aeson.cabal +26/−40
- benchmarks/AesonEncode.hs +1/−1
- benchmarks/AesonParse.hs +1/−1
- benchmarks/Compare.hs +26/−0
- benchmarks/Compare/BufferBuilder.hs +59/−0
- benchmarks/Compare/JsonBench.hs +325/−0
- benchmarks/Compare/JsonBuilder.hs +64/−0
- benchmarks/CompareWithJSON.hs +7/−1
- benchmarks/Dates.hs +39/−0
- benchmarks/Micro.hs +18/−0
- benchmarks/Typed.hs +13/−0
- benchmarks/Typed/Common.hs +16/−0
- benchmarks/Typed/Generic.hs +29/−0
- benchmarks/Typed/Manual.hs +29/−0
- benchmarks/Typed/TH.hs +29/−0
- benchmarks/aeson-benchmarks.cabal +65/−9
- benchmarks/json-data/buffer-builder.json +4322/−0
- benchmarks/json-data/dates-fract.json +1/−0
- benchmarks/json-data/dates.json +1/−0
- benchmarks/json-data/jp10.json +0/−0
- benchmarks/json-data/jp100.json +0/−0
- benchmarks/json-data/jp50.json +0/−0
- benchmarks/json-data/twitter1.json +0/−0
- benchmarks/json-data/twitter10.json +0/−0
- benchmarks/json-data/twitter100.json +1/−1
- benchmarks/json-data/twitter20.json +1/−1
- benchmarks/json-data/twitter50.json +1/−1
- changelog.md +152/−70
- examples/Generic.hs +0/−3
- examples/GenericSYB.hs +0/−30
- examples/Simplest.hs +6/−1
- examples/Twitter.hs +74/−0
- examples/Twitter/Generic.hs +26/−0
- examples/Twitter/Manual.hs +141/−0
- examples/Twitter/TH.hs +20/−0
- examples/aeson-examples.cabal +29/−0
- tests/DataFamilies/Encoders.hs +114/−0
- tests/DataFamilies/Types.hs +25/−0
- tests/Encoders.hs +79/−22
- tests/Instances.hs +13/−5
- tests/Options.hs +5/−0
- tests/Properties.hs +112/−240
- tests/Properties/Deprecated.hs +0/−57
- tests/Tests.hs +11/−0
- tests/Types.hs +6/−7
- tests/UnitTests.hs +186/−0
Data/Aeson.hs view
@@ -1,8 +1,6 @@-{-# LANGUAGE CPP #-}- -- | -- Module: Data.Aeson--- Copyright: (c) 2011, 2012 Bryan O'Sullivan+-- Copyright: (c) 2011-2015 Bryan O'Sullivan -- (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Bryan O'Sullivan <bos@serpentine.com>@@ -18,6 +16,9 @@ -- * How to use this library -- $use + -- ** Writing instances by hand+ -- $manual+ -- ** Working with the AST -- $ast @@ -27,14 +28,11 @@ -- ** Decoding a mixed-type object -- $mixed - -- ** Automatically decoding data types- -- $typeable-- -- ** Pitfalls- -- $pitfalls- -- * Encoding and decoding -- $encoding_and_decoding++ -- ** Direct encoding+ -- $encoding decode , decode' , eitherDecode@@ -47,6 +45,8 @@ , eitherDecodeStrict' -- * Core JSON types , Value(..)+ , Encoding+ , fromEncoding , Array , Object -- * Convenience types@@ -56,13 +56,15 @@ , Result(..) , fromJSON , ToJSON(..)-#ifdef GENERICS- -- ** Generic JSON classes+ , KeyValue(..)+ -- ** Generic JSON classes and options , GFromJSON(..) , GToJSON(..) , genericToJSON+ , genericToEncoding , genericParseJSON-#endif+ , defaultOptions+ -- * Inspecting @'Value's@ , withObject , withText@@ -71,7 +73,9 @@ , withScientific , withBool -- * Constructors and accessors- , (.=)+ , Series+ , pairs+ , foldable , (.:) , (.:?) , (.!=)@@ -86,6 +90,8 @@ eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json') import Data.Aeson.Types+import Data.Aeson.Types.Instances (ifromJSON)+import Data.Aeson.Types.Internal (JSONPath, formatError) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L @@ -120,10 +126,7 @@ -- returned. -- -- The input must consist solely of a JSON document, with no trailing--- data except for whitespace. This restriction is necessary to ensure--- that if data is being lazily read from a file handle, the file--- handle will be closed in a timely fashion once the document has--- been parsed.+-- data except for whitespace. -- -- This function parses and performs conversion immediately. See -- 'json'' for details.@@ -144,44 +147,94 @@ decodeStrict' = decodeStrictWith jsonEOF' fromJSON {-# INLINE decodeStrict' #-} +eitherFormatError :: Either (JSONPath, String) a -> Either String a+eitherFormatError = either (Left . uncurry formatError) Right+{-# INLINE eitherFormatError #-}+ -- | Like 'decode' but returns an error message when decoding fails. eitherDecode :: (FromJSON a) => L.ByteString -> Either String a-eitherDecode = eitherDecodeWith jsonEOF fromJSON+eitherDecode = eitherFormatError . eitherDecodeWith jsonEOF ifromJSON {-# INLINE eitherDecode #-} -- | Like 'decodeStrict' but returns an error message when decoding fails. eitherDecodeStrict :: (FromJSON a) => B.ByteString -> Either String a-eitherDecodeStrict = eitherDecodeStrictWith jsonEOF fromJSON+eitherDecodeStrict =+ eitherFormatError . eitherDecodeStrictWith jsonEOF ifromJSON {-# INLINE eitherDecodeStrict #-} -- | Like 'decode'' but returns an error message when decoding fails. eitherDecode' :: (FromJSON a) => L.ByteString -> Either String a-eitherDecode' = eitherDecodeWith jsonEOF' fromJSON+eitherDecode' = eitherFormatError . eitherDecodeWith jsonEOF' ifromJSON {-# INLINE eitherDecode' #-} -- | Like 'decodeStrict'' but returns an error message when decoding fails. eitherDecodeStrict' :: (FromJSON a) => B.ByteString -> Either String a-eitherDecodeStrict' = eitherDecodeStrictWith jsonEOF' fromJSON+eitherDecodeStrict' =+ eitherFormatError . eitherDecodeStrictWith jsonEOF' ifromJSON {-# INLINE eitherDecodeStrict' #-} -- $use -- -- This section contains basic information on the different ways to--- decode data using this library. These range from simple but+-- work with data using this library. These range from simple but -- inflexible, to complex but flexible. -- -- The most common way to use the library is to define a data type, -- corresponding to some JSON data you want to work with, and then -- write either a 'FromJSON' instance, a to 'ToJSON' instance, or both--- for that type. For example, given this JSON data:+-- for that type. --+-- For example, given this JSON data:+-- -- > { "name": "Joe", "age": 12 } -- -- we create a matching data type: ----- > data Person = Person--- > { name :: Text+-- > {-# LANGUAGE DeriveGeneric #-}+-- >+-- > import GHC.Generics+-- >+-- > data Person = Person {+-- > name :: Text -- > , age :: Int+-- > } deriving (Generic, Show)+--+-- The @LANGUAGE@ pragma and 'Generic' instance let us write empty+-- 'FromJSON' and 'ToJSON' instances for which the compiler will+-- generate sensible default implementations.+--+-- @+-- instance 'ToJSON' Person where+-- \-- No need to provide a 'toJSON' implementation.+--+-- \-- For efficiency, we write a simple 'toEncoding' implementation, as+-- \-- the default version uses 'toJSON'.+-- 'toEncoding' = 'genericToEncoding' 'defaultOptions'+--+-- instance 'FromJSON' Person+-- \-- No need to provide a 'parseJSON' implementation.+-- @+--+-- We can now encode a value like so:+--+-- > >>> encode (Person {name = "Joe", age = 12})+-- > "{\"name\":\"Joe\",\"age\":12}"++-- $manual+--+-- When necessary, we can write 'ToJSON' and 'FromJSON' instances by+-- hand. This is valuable when the JSON-on-the-wire and Haskell data+-- are different or otherwise need some more carefully managed+-- translation. Let's revisit our JSON data:+--+-- > { "name": "Joe", "age": 12 }+--+-- We once again create a matching data type, without bothering to add+-- a 'Generic' instance this time:+--+-- > data Person = Person {+-- > name :: Text+-- > , age :: Int -- > } deriving Show -- -- To decode data, we need to define a 'FromJSON' instance:@@ -193,18 +246,27 @@ -- > v .: "name" <*> -- > v .: "age" -- > -- A non-Object value is of the wrong type, so fail.--- > parseJSON _ = mzero+-- > parseJSON _ = empty -- -- We can now parse the JSON data like so: -- -- > >>> decode "{\"name\":\"Joe\",\"age\":12}" :: Maybe Person -- > Just (Person {name = "Joe", age = 12}) ----- To encode data, we need to define a 'ToJSON' instance:+-- To encode data, we need to define a 'ToJSON' instance. Let's begin+-- with an instance written entirely by hand. ----- > instance ToJSON Person where--- > toJSON (Person name age) = object ["name" .= name, "age" .= age]+-- @+-- instance ToJSON Person where+-- \-- this generates a 'Value'+-- 'toJSON' (Person name age) =+-- 'object' [\"name\" '.=' name, \"age\" '.=' age] --+-- \-- this encodes directly to a bytestring Builder+-- 'toEncoding' (Person name age) =+-- 'pairs' (\"name\" '.=' 'name' '<>' \"age\" '.=' age)+-- @+-- -- We can now encode a value like so: -- -- > >>> encode (Person {name = "Joe", age = 12})@@ -229,7 +291,7 @@ -- expectations.) -- -- See the documentation of 'FromJSON' and 'ToJSON' for some examples--- of how you can automatically derive instances in some+-- of how you can automatically derive instances in many common -- circumstances. -- $ast@@ -252,8 +314,7 @@ -- $haskell ----- Any instance of 'FromJSON' can be specified (but see the--- \"Pitfalls\" section here—"Data.Aeson#pitfalls"):+-- We can decode to any instance of 'FromJSON': -- -- > λ> decode "[1,2,3]" :: Maybe [Int] -- > Just [1,2,3]@@ -262,7 +323,7 @@ -- can use them directly. For example, use the 'Data.Map.Map' type to -- get a map of 'Int's. ----- > λ> :m + Data.Map+-- > λ> import Data.Map -- > λ> decode "{\"foo\":1,\"bar\":2}" :: Maybe (Map String Int) -- > Just (fromList [("bar",2),("foo",1)]) @@ -297,86 +358,68 @@ -- upside is that you have complete control over the way the JSON is -- parsed. --- $typeable+-- $encoding_and_decoding ----- If you don't want fine control and would prefer the JSON be parsed--- to your own data types automatically according to some reasonably--- sensible isomorphic implementation, you can use the generic parser--- based on 'Data.Typeable.Typeable' and 'Data.Data.Data'. Switch to--- the 'Data.Aeson.Generic' module, and you can do the following:+-- Decoding is a two-step process. ----- > λ> decode "[1]" :: Maybe [Int]--- > Just [1]--- > λ> :m + Data.Typeable Data.Data--- > λ> :set -XDeriveDataTypeable--- > λ> data Person = Person { personName :: String, personAge :: Int } deriving (Data,Typeable,Show)--- > λ> encode Person { personName = "Chris", personAge = 123 }--- > "{\"personAge\":123,\"personName\":\"Chris\"}"--- > λ> decode "{\"personAge\":123,\"personName\":\"Chris\"}" :: Maybe Person--- > Just (Person {--- > personName = "Chris", personAge = 123--- > })+-- * When decoding a value, the process is reversed: the bytes are+-- converted to a 'Value', then the 'FromJSON' class is used to+-- convert to the desired type. ----- Be aware that the encoding may not always be what you'd naively--- expect:+-- There are two ways to encode a value. ----- > λ> data Foo = Foo Int Int deriving (Data,Typeable,Show)--- > λ> encode (Foo 1 2)--- > "[1,2]"+-- * Convert to a 'Value' using 'toJSON', then possibly further+-- encode. This was the only method available in aeson 0.9 and+-- earlier. ----- With this approach, it's best to treat the--- 'Data.Aeson.Generic.decode' and 'Data.Aeson.Generic.encode'--- functions as an isomorphism, and not to rely upon (or care about)--- the specific intermediate representation.---- $pitfalls--- #pitfalls#+-- * Directly encode (to what will become a 'L.ByteString') using+-- 'toEncoding'. This is much more efficient (about 3x faster, and+-- less memory intensive besides), but is only available in aeson+-- 0.10 and newer. ----- Note that the JSON standard requires that the top-level value be--- either an array or an object. If you try to use 'decode' with a--- result type that is /not/ represented in JSON as an array or--- object, your code will typecheck, but it will always \"fail\" at--- runtime:+-- For convenience, the 'encode' and 'decode' functions combine both+-- steps.++-- $encoding ----- > >>> decode "1" :: Maybe Int--- > Nothing--- > >>> decode "1" :: Maybe String--- > Nothing+-- In older versions of this library, encoding a Haskell value+-- involved converting to an intermediate 'Value', then encoding that. ----- So stick to objects (e.g. maps in Haskell) or arrays (lists or--- vectors in Haskell):+-- A \"direct\" encoder converts straight from a source Haskell value+-- to a 'BL.ByteString' without constructing an intermediate 'Value'.+-- This approach is faster than 'toJSON', and allocates less memory.+-- The 'toEncoding' method makes it possible to implement direct+-- encoding with low memory overhead. ----- > >>> decode "[1,2,3]" :: Maybe [Int]--- > Just [1,2,3]+-- To complicate matters, the default implementation of 'toEncoding'+-- uses 'toJSON'. Why? The 'toEncoding' method was added to this+-- library much more recently than 'toJSON'. Using 'toJSON' ensures+-- that packages written against older versions of this library will+-- compile and produce correct output, but they will not see any+-- speedup from direct encoding. ----- When encoding to JSON you can encode anything that's an instance of--- 'ToJSON', and this may include simple types. So beware that this--- aspect of the API is not isomorphic. You can round-trip arrays and--- maps, but not simple values:+-- To write a minimal implementation of direct encoding, your type+-- must implement GHC's 'Generic' class, and your code should look+-- like this: ----- > >>> encode [1,2,3]--- > "[1,2,3]"--- > >>> decode (encode [1]) :: Maybe [Int]--- > Just [1]--- > >>> encode 1--- > "1"--- > >>> decode (encode (1 :: Int)) :: Maybe Int--- > Nothing+-- @+-- 'toEncoding' = 'genericToEncoding' 'defaultOptions'+-- @ ----- Alternatively, see 'Data.Aeson.Parser.value' to parse non-top-level--- JSON values.---- $encoding_and_decoding+-- What if you have more elaborate encoding needs? For example,+-- perhaps you need to change the names of object keys, omit parts of+-- a value. ----- Encoding and decoding are each two-step processes.+-- To encode to a JSON \"object\", use the 'pairs' function. ----- * To encode a value, it is first converted to an abstract syntax--- tree (AST), using 'ToJSON'. This generic representation is then--- encoded as bytes.+-- @+-- 'toEncoding' (Person name age) =+-- 'pairs' (\"name\" '.=' 'name' '<>' \"age\" '.=' age)+-- @ ----- * When decoding a value, the process is reversed: the bytes are--- converted to an AST, then the 'FromJSON' class is used to convert--- to the desired type.+-- Any container type that implements 'Foldable' can be encoded to a+-- JSON \"array\" using 'foldable'. ----- For convenience, the 'encode' and 'decode' functions combine both--- steps.+-- > > import Data.Sequence as Seq+-- > > encode (Seq.fromList [1,2,3])+-- > "[1,2,3]"
Data/Aeson/Encode.hs view
@@ -2,7 +2,7 @@ -- | -- Module: Data.Aeson.Encode--- Copyright: (c) 2012 Bryan O'Sullivan+-- Copyright: (c) 2012-2015 Bryan O'Sullivan -- (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Bryan O'Sullivan <bos@serpentine.com>@@ -21,15 +21,16 @@ -- * Encoding to Builders , encodeToBuilder- , encodeToByteStringBuilder , encodeToTextBuilder -- * Deprecated , fromValue ) where +import Data.Aeson.Encode.Builder (encodeToBuilder)+import Data.Aeson.Encode.Functions (encode) import Data.Aeson.Types (Value(..))-import Data.Monoid (mappend)+import Data.Monoid ((<>)) import Data.Scientific (FPFormat(..), Scientific, base10Exponent) import Data.Text.Lazy.Builder import Data.Text.Lazy.Builder.Scientific (formatScientificBuilder)@@ -38,11 +39,12 @@ import qualified Data.Text as T import qualified Data.Vector as V -import Data.Aeson.Encode.ByteString (encode, encodeToBuilder,- encodeToByteStringBuilder)- -- | Encode a JSON 'Value' to a "Data.Text" 'Builder', which can be -- embedded efficiently in a text-based protocol.+--+-- If you are going to immediately encode straight to a+-- 'L.ByteString', it is more efficient to use 'encodeToBuilder'+-- instead. encodeToTextBuilder :: Value -> Builder encodeToTextBuilder = go@@ -96,8 +98,3 @@ (format, prec) | base10Exponent s < 0 = (Generic, Nothing) | otherwise = (Fixed, Just 0)--(<>) :: Builder -> Builder -> Builder-(<>) = mappend-{-# INLINE (<>) #-}-infixr 6 <>
+ Data/Aeson/Encode/Builder.hs view
@@ -0,0 +1,254 @@+{-# LANGUAGE BangPatterns, OverloadedStrings #-}++-- |+-- Module: Data.Aeson.Encode.Builder+-- Copyright: (c) 2011 MailRank, Inc.+-- (c) 2013 Simon Meier <iridcode@gmail.com>+-- License: Apache+-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>+-- Stability: experimental+-- Portability: portable+--+-- Efficiently serialize a JSON value using the UTF-8 encoding.++module Data.Aeson.Encode.Builder+ (+ encodeToBuilder+ , null_+ , bool+ , array+ , emptyArray_+ , emptyObject_+ , object+ , text+ , string+ , unquoted+ , number+ , day+ , localTime+ , utcTime+ , timeOfDay+ , zonedTime+ , ascii2+ , ascii4+ , ascii5+ ) where++import Data.Aeson.Internal.Time+import Data.Aeson.Types.Internal (Encoding(..), Value(..))+import Data.ByteString.Builder as B+import Data.ByteString.Builder.Prim as BP+import Data.ByteString.Builder.Scientific (scientificBuilder)+import Data.Char (chr, ord)+import Data.Monoid ((<>))+import Data.Scientific (Scientific, base10Exponent, coefficient)+import Data.Time (UTCTime(..))+import Data.Time.Calendar (Day(..), toGregorian)+import Data.Time.LocalTime+import Data.Word (Word8)+import qualified Data.HashMap.Strict as HMS+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import qualified Data.Vector as V++-- | Encode a JSON value to a "Data.ByteString" 'B.Builder'.+--+-- Use this function if you are encoding over the wire, or need to+-- prepend or append further bytes to the encoded JSON value.+encodeToBuilder :: Value -> Builder+encodeToBuilder Null = null_+encodeToBuilder (Bool b) = bool b+encodeToBuilder (Number n) = number n+encodeToBuilder (String s) = text s+encodeToBuilder (Array v) = array v+encodeToBuilder (Object m) = object m++-- | Encode a JSON null.+null_ :: Builder+null_ = BP.primBounded (ascii4 ('n',('u',('l','l')))) ()++-- | Encode a JSON boolean.+bool :: Bool -> Builder+bool = BP.primBounded (BP.condB id (ascii4 ('t',('r',('u','e'))))+ (ascii5 ('f',('a',('l',('s','e'))))))++-- | Encode a JSON array.+array :: V.Vector Value -> Builder+array v+ | V.null v = emptyArray__+ | otherwise = B.char8 '[' <>+ encodeToBuilder (V.unsafeHead v) <>+ V.foldr withComma (B.char8 ']') (V.unsafeTail v)+ where+ withComma a z = B.char8 ',' <> encodeToBuilder a <> z++-- Encode a JSON object.+object :: HMS.HashMap T.Text Value -> Builder+object m = case HMS.toList m of+ (x:xs) -> B.char8 '{' <> one x <> foldr withComma (B.char8 '}') xs+ _ -> emptyObject__+ where+ withComma a z = B.char8 ',' <> one a <> z+ one (k,v) = text k <> B.char8 ':' <> encodeToBuilder v++-- | Encode a JSON string.+text :: T.Text -> Builder+text t = B.char8 '"' <> unquoted t <> B.char8 '"'++-- | Encode a JSON string, without enclosing quotes.+unquoted :: T.Text -> Builder+unquoted t = TE.encodeUtf8BuilderEscaped escapeAscii t++-- | Encode a JSON string.+string :: String -> Builder+string t = B.char8 '"' <> BP.primMapListBounded go t <> B.char8 '"'+ where go = BP.condB (> '\x7f') BP.charUtf8 (c2w >$< escapeAscii)++escapeAscii :: BP.BoundedPrim Word8+escapeAscii =+ BP.condB (== c2w '\\' ) (ascii2 ('\\','\\')) $+ BP.condB (== c2w '\"' ) (ascii2 ('\\','"' )) $+ BP.condB (>= c2w '\x20') (BP.liftFixedToBounded BP.word8) $+ BP.condB (== c2w '\n' ) (ascii2 ('\\','n' )) $+ BP.condB (== c2w '\r' ) (ascii2 ('\\','r' )) $+ BP.condB (== c2w '\t' ) (ascii2 ('\\','t' )) $+ (BP.liftFixedToBounded hexEscape) -- fallback for chars < 0x20+ where+ hexEscape :: BP.FixedPrim Word8+ hexEscape = (\c -> ('\\', ('u', fromIntegral c))) BP.>$<+ BP.char8 >*< BP.char8 >*< BP.word16HexFixed+{-# INLINE escapeAscii #-}++c2w :: Char -> Word8+c2w c = fromIntegral (ord c)++-- | Encode a JSON number.+number :: Scientific -> Builder+number s+ | e < 0 = scientificBuilder s+ | otherwise = B.integerDec (coefficient s * 10 ^ e)+ where+ e = base10Exponent s++emptyArray_ :: Encoding+emptyArray_ = Encoding emptyArray__++emptyArray__ :: Builder+emptyArray__ = BP.primBounded (ascii2 ('[',']')) ()++emptyObject_ :: Encoding+emptyObject_ = Encoding emptyObject__++emptyObject__ :: Builder+emptyObject__ = BP.primBounded (ascii2 ('{','}')) ()++ascii2 :: (Char, Char) -> BP.BoundedPrim a+ascii2 cs = BP.liftFixedToBounded $ (const cs) BP.>$< BP.char7 >*< BP.char7+{-# INLINE ascii2 #-}++ascii4 :: (Char, (Char, (Char, Char))) -> BP.BoundedPrim a+ascii4 cs = BP.liftFixedToBounded $ (const cs) >$<+ BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7+{-# INLINE ascii4 #-}++ascii5 :: (Char, (Char, (Char, (Char, Char)))) -> BP.BoundedPrim a+ascii5 cs = BP.liftFixedToBounded $ (const cs) >$<+ BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7+{-# INLINE ascii5 #-}++ascii6 :: (Char, (Char, (Char, (Char, (Char, Char))))) -> BP.BoundedPrim a+ascii6 cs = BP.liftFixedToBounded $ (const cs) >$<+ BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7+{-# INLINE ascii6 #-}++ascii8 :: (Char, (Char, (Char, (Char, (Char, (Char, (Char, Char)))))))+ -> BP.BoundedPrim a+ascii8 cs = BP.liftFixedToBounded $ (const cs) >$<+ BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*<+ BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7+{-# INLINE ascii8 #-}++day :: Day -> Builder+day dd = encodeYear yr <>+ BP.primBounded (ascii6 ('-',(mh,(ml,('-',(dh,dl)))))) ()+ where (yr,m,d) = toGregorian dd+ !(T mh ml) = twoDigits m+ !(T dh dl) = twoDigits d+ encodeYear y+ | y >= 1000 = B.integerDec y+ | y > 0 =+ let (ab,c) = fromIntegral y `quotRem` 10+ (a,b) = ab `quotRem` 10+ in BP.primBounded (ascii4 ('0',(digit a,(digit b,digit c)))) ()+ | otherwise =+ error "Data.Aeson.Encode.Builder.day: years BCE not supported"+{-# INLINE day #-}++timeOfDay :: TimeOfDay -> Builder+timeOfDay t = timeOfDay64 (toTimeOfDay64 t)+{-# INLINE timeOfDay #-}++timeOfDay64 :: TimeOfDay64 -> Builder+timeOfDay64 (TOD h m s)+ | frac == 0 = hhmmss -- omit subseconds if 0+ | otherwise = hhmmss <> BP.primBounded showFrac frac+ where+ hhmmss = BP.primBounded (ascii8 (hh,(hl,(':',(mh,(ml,(':',(sh,sl)))))))) ()+ !(T hh hl) = twoDigits h+ !(T mh ml) = twoDigits m+ !(T sh sl) = twoDigits (fromIntegral real)+ (real,frac) = s `quotRem` pico+ showFrac = (\x -> ('.', x)) >$< (BP.liftFixedToBounded BP.char7 >*< trunc12)+ trunc12 = (`quotRem` micro) >$<+ BP.condB (\(_,y) -> y == 0) (fst >$< trunc6) (digits6 >*< trunc6)+ digits6 = ((`quotRem` milli) . fromIntegral) >$< (digits3 >*< digits3)+ trunc6 = ((`quotRem` milli) . fromIntegral) >$<+ BP.condB (\(_,y) -> y == 0) (fst >$< trunc3) (digits3 >*< trunc3)+ digits3 = (`quotRem` 10) >$< (digits2 >*< digits1)+ digits2 = (`quotRem` 10) >$< (digits1 >*< digits1)+ digits1 = BP.liftFixedToBounded (digit >$< BP.char7)+ trunc3 = BP.condB (== 0) BP.emptyB $+ (`quotRem` 100) >$< (digits1 >*< trunc2)+ trunc2 = BP.condB (== 0) BP.emptyB $+ (`quotRem` 10) >$< (digits1 >*< trunc1)+ trunc1 = BP.condB (== 0) BP.emptyB digits1++ pico = 1000000000000 -- number of picoseconds in 1 second+ micro = 1000000 -- number of microseconds in 1 second+ milli = 1000 -- number of milliseconds in 1 second+{-# INLINE timeOfDay64 #-}++timeZone :: TimeZone -> Builder+timeZone (TimeZone off _ _)+ | off == 0 = B.char7 'Z'+ | otherwise = BP.primBounded (ascii6 (s,(hh,(hl,(':',(mh,ml)))))) ()+ where !s = if off < 0 then '-' else '+'+ !(T hh hl) = twoDigits h+ !(T mh ml) = twoDigits m+ (h,m) = abs off `quotRem` 60+{-# INLINE timeZone #-}++dayTime :: Day -> TimeOfDay64 -> Builder+dayTime d t = day d <> B.char7 'T' <> timeOfDay64 t+{-# INLINE dayTime #-}++utcTime :: UTCTime -> B.Builder+utcTime (UTCTime d s) = dayTime d (diffTimeOfDay64 s) <> B.char7 'Z'+{-# INLINE utcTime #-}++localTime :: LocalTime -> Builder+localTime (LocalTime d t) = dayTime d (toTimeOfDay64 t)+{-# INLINE localTime #-}++zonedTime :: ZonedTime -> Builder+zonedTime (ZonedTime t z) = localTime t <> timeZone z+{-# INLINE zonedTime #-}++data T = T {-# UNPACK #-} !Char {-# UNPACK #-} !Char++twoDigits :: Int -> T+twoDigits a = T (digit hi) (digit lo)+ where (hi,lo) = a `quotRem` 10++digit :: Int -> Char+digit x = chr (x + 48)
− Data/Aeson/Encode/ByteString.hs
@@ -1,123 +0,0 @@-{-# LANGUAGE BangPatterns, OverloadedStrings #-}---- |--- Module: Data.Aeson.EncodeUtf8--- Copyright: (c) 2011 MailRank, Inc.--- (c) 2013 Simon Meier <iridcode@gmail.com>--- License: Apache--- Maintainer: Bryan O'Sullivan <bos@serpentine.com>--- Stability: experimental--- Portability: portable------ Efficiently serialize a JSON value using the UTF-8 encoding.--module Data.Aeson.Encode.ByteString- ( encode- , encodeToBuilder- , encodeToByteStringBuilder- ) where--import Prelude hiding (null)-import Data.Aeson.Types (ToJSON(..), Value(..))-import Data.Char (ord)-import Data.Scientific (Scientific, coefficient, base10Exponent)-import Data.Word (Word8)-import Data.Monoid (mappend)-import Data.ByteString.Builder as B-import Data.ByteString.Builder.Prim as BP-import Data.ByteString.Builder.Scientific (scientificBuilder)-import qualified Data.ByteString.Lazy as L-import qualified Data.HashMap.Strict as HMS-import qualified Data.Text as T-import qualified Data.Text.Encoding as TE-import qualified Data.Vector as V--(<>) :: Builder -> Builder -> Builder-(<>) = mappend-{-# INLINE (<>) #-}-infixr 6 <>---- | Efficiently serialize a JSON value as a lazy 'L.ByteString'.-encode :: ToJSON a => a -> L.ByteString-encode = B.toLazyByteString . encodeToBuilder . toJSON---- | Encode a JSON value to a ByteString 'B.Builder'. Use this function if you--- must prepend or append further bytes to the encoded JSON value.-encodeToBuilder :: Value -> Builder-encodeToBuilder Null = null-encodeToBuilder (Bool b) = bool b-encodeToBuilder (Number n) = number n-encodeToBuilder (String s) = string s-encodeToBuilder (Array v) = array v-encodeToBuilder (Object m) = object m---- | This function is an alias for 'encodeToBuilder'.-encodeToByteStringBuilder :: Value -> Builder-encodeToByteStringBuilder = encodeToBuilder-{-# DEPRECATED encodeToByteStringBuilder "Use encodeToBuilder instead." #-}--null :: Builder-null = BP.primBounded (ascii4 ('n',('u',('l','l')))) ()--bool :: Bool -> Builder-bool = BP.primBounded (BP.condB id (ascii4 ('t',('r',('u','e'))))- (ascii5 ('f',('a',('l',('s','e'))))))--array :: V.Vector Value -> Builder-array v- | V.null v = B.char8 '[' <> B.char8 ']'- | otherwise = B.char8 '[' <>- encodeToByteStringBuilder (V.unsafeHead v) <>- V.foldr withComma (B.char8 ']') (V.unsafeTail v)- where- withComma a z = B.char8 ',' <> encodeToByteStringBuilder a <> z--object :: HMS.HashMap T.Text Value -> Builder-object m = case HMS.toList m of- (x:xs) -> B.char8 '{' <> one x <> foldr withComma (B.char8 '}') xs- _ -> B.char8 '{' <> B.char8 '}'- where- withComma a z = B.char8 ',' <> one a <> z- one (k,v) = string k <> B.char8 ':' <> encodeToByteStringBuilder v--string :: T.Text -> B.Builder-string t =- B.char8 '"' <> TE.encodeUtf8BuilderEscaped escapeAscii t <> B.char8 '"'- where- escapeAscii :: BP.BoundedPrim Word8- escapeAscii =- BP.condB (== c2w '\\' ) (ascii2 ('\\','\\')) $- BP.condB (== c2w '\"' ) (ascii2 ('\\','"' )) $- BP.condB (>= c2w '\x20') (BP.liftFixedToBounded BP.word8) $- BP.condB (== c2w '\n' ) (ascii2 ('\\','n' )) $- BP.condB (== c2w '\r' ) (ascii2 ('\\','r' )) $- BP.condB (== c2w '\t' ) (ascii2 ('\\','t' )) $- (BP.liftFixedToBounded hexEscape) -- fallback for chars < 0x20-- c2w = fromIntegral . ord-- hexEscape :: BP.FixedPrim Word8- hexEscape = (\c -> ('\\', ('u', fromIntegral c))) BP.>$<- BP.char8 BP.>*< BP.char8 BP.>*< BP.word16HexFixed--number :: Scientific -> Builder-number s- | e < 0 = scientificBuilder s- | otherwise = B.integerDec (coefficient s * 10 ^ e)- where- e = base10Exponent s---{-# INLINE ascii2 #-}-ascii2 :: (Char, Char) -> BP.BoundedPrim a-ascii2 cs = BP.liftFixedToBounded $ (const cs) BP.>$< BP.char7 BP.>*< BP.char7--{-# INLINE ascii4 #-}-ascii4 :: (Char, (Char, (Char, Char))) -> BP.BoundedPrim a-ascii4 cs = BP.liftFixedToBounded $ (const cs) >$<- BP.char7 BP.>*< BP.char7 BP.>*< BP.char7 BP.>*< BP.char7--{-# INLINE ascii5 #-}-ascii5 :: (Char, (Char, (Char, (Char, Char)))) -> BP.BoundedPrim a-ascii5 cs = BP.liftFixedToBounded $ (const cs) >$<- BP.char7 BP.>*< BP.char7 BP.>*< BP.char7 BP.>*< BP.char7 BP.>*< BP.char7
+ Data/Aeson/Encode/Functions.hs view
@@ -0,0 +1,53 @@+module Data.Aeson.Encode.Functions+ (+ brackets+ , builder+ , char7+ , encode+ , foldable+ , list+ , pairs+ ) where++import Data.Aeson.Encode.Builder+import Data.Aeson.Types.Class+import Data.Aeson.Types.Internal+import Data.ByteString.Builder (Builder, char7)+import Data.ByteString.Builder.Prim (primBounded)+import Data.Foldable (Foldable, foldMap)+import Data.Monoid ((<>), mempty)+import qualified Data.ByteString.Builder as B+import qualified Data.ByteString.Lazy as L++builder :: ToJSON a => a -> Builder+builder = fromEncoding . toEncoding+{-# INLINE builder #-}++-- | Efficiently serialize a JSON value as a lazy 'L.ByteString'.+--+-- This is implemented in terms of the 'ToJSON' class's 'toEncoding' method.+encode :: ToJSON a => a -> L.ByteString+encode = B.toLazyByteString . builder+{-# INLINE encode #-}++-- | Encode a 'Foldable' as a JSON array.+foldable :: (Foldable t, ToJSON a) => t a -> Encoding+foldable = brackets '[' ']' . foldMap (Value . toEncoding)+{-# INLINE foldable #-}++list :: (ToJSON a) => [a] -> Encoding+list [] = emptyArray_+list (x:xs) = Encoding $+ char7 '[' <> builder x <> commas xs <> char7 ']'+ where commas = foldr (\v vs -> char7 ',' <> builder v <> vs) mempty+{-# INLINE list #-}++brackets :: Char -> Char -> Series -> Encoding+brackets begin end (Value v) = Encoding $+ char7 begin <> fromEncoding v <> char7 end+brackets begin end Empty = Encoding (primBounded (ascii2 (begin,end)) ())++-- | Encode a series of key/value pairs, separated by commas.+pairs :: Series -> Encoding+pairs s = brackets '{' '}' s+{-# INLINE pairs #-}
Data/Aeson/Functions.hs view
@@ -1,6 +1,6 @@ -- | -- Module: Data.Aeson.Functions--- Copyright: (c) 2011, 2012 Bryan O'Sullivan+-- Copyright: (c) 2011-2015 Bryan O'Sullivan -- (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Bryan O'Sullivan <bos@serpentine.com>
− Data/Aeson/Generic.hs
@@ -1,368 +0,0 @@-{-# LANGUAGE PatternGuards, Rank2Types, ScopedTypeVariables, CPP #-}---- TODO: Drop this when we remove support for Data.Attoparsec.Number-#if MIN_VERSION_attoparsec(0,12,0)-{-# OPTIONS_GHC -fno-warn-deprecations #-}-#endif---- |--- Module: Data.Aeson.Generic--- Copyright: (c) 2011, 2012, 2013 Bryan O'Sullivan--- (c) 2011 MailRank, Inc.--- (c) 2008, 2009 Lennart Augustsson--- License: BSD3--- Maintainer: Bryan O'Sullivan <bos@serpentine.com>--- Stability: DEPRECATED--- Portability: portable------ JSON handling using 'Data.Generics'.------ This is based on the 'Text.JSON.Generic' package originally written--- by Lennart Augustsson.--module Data.Aeson.Generic-{-# DEPRECATED "This module will be /REMOVED/ in version 0.7.0.0. Please switch to GHC generics or Data.Aeson.TH instead. These alternatives are less buggy, faster, and more configurable." #-}- (- -- * Decoding and encoding- decode- , decode'- , encode- -- * Lower-level conversion functions- , fromJSON- , toJSON- ) where--import Control.Applicative ((<$>))-import Control.Arrow (first)-import Control.Monad.State.Strict-import Data.Aeson.Functions-import Data.Aeson.Types hiding (FromJSON(..), ToJSON(..), fromJSON)-import Data.Attoparsec.Number (Number)-import Data.Generics-import Data.Hashable (Hashable)-import Data.Int (Int8, Int16, Int32, Int64)-import Data.IntSet (IntSet)-import Data.Maybe (fromJust)-import Data.Text (Text, pack, unpack)-import Data.Time.Clock (UTCTime)-import Data.Word (Word, Word8, Word16, Word32, Word64)-import Data.Aeson.Parser.Internal (decodeWith, json, json')-import qualified Data.Aeson.Encode as E-import qualified Data.Aeson.Types as T-import qualified Data.ByteString.Lazy as L-import qualified Data.HashMap.Strict as H-import qualified Data.Map as Map-import qualified Data.Set as Set-import qualified Data.Text as DT-import qualified Data.Text.Lazy as LT-import qualified Data.Traversable as T-import qualified Data.Vector as V---- | Efficiently serialize a JSON value as a lazy 'L.ByteString'.-encode :: (Data a) => a -> L.ByteString-encode = E.encode . toJSON-{-# INLINE encode #-}---- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.--- If this fails due to incomplete or invalid input, 'Nothing' is--- returned.------ This function parses immediately, but defers conversion. See--- 'json' for details.-decode :: (Data a) => L.ByteString -> Maybe a-decode = decodeWith json fromJSON-{-# INLINE decode #-}---- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.--- If this fails due to incomplete or invalid input, 'Nothing' is--- returned.------ This function parses and performs conversion immediately. See--- 'json'' for details.-decode' :: (Data a) => L.ByteString -> Maybe a-decode' = decodeWith json' fromJSON-{-# INLINE decode' #-}--type T a = a -> Value--toJSON :: (Data a) => a -> Value-toJSON = toJSON_generic- `ext1Q` maybe Null toJSON- `ext1Q` list- `ext1Q` vector- `ext1Q` set- `ext2Q'` mapAny- `ext2Q'` hashMapAny- -- Use the standard encoding for all base types.- `extQ` (T.toJSON :: T Integer)- `extQ` (T.toJSON :: T Int)- `extQ` (T.toJSON :: T Int8)- `extQ` (T.toJSON :: T Int16)- `extQ` (T.toJSON :: T Int32)- `extQ` (T.toJSON :: T Int64)- `extQ` (T.toJSON :: T Word)- `extQ` (T.toJSON :: T Word8)- `extQ` (T.toJSON :: T Word16)- `extQ` (T.toJSON :: T Word32)- `extQ` (T.toJSON :: T Word64)- `extQ` (T.toJSON :: T Double)- `extQ` (T.toJSON :: T Number)- `extQ` (T.toJSON :: T Float)- `extQ` (T.toJSON :: T Rational)- `extQ` (T.toJSON :: T Char)- `extQ` (T.toJSON :: T Text)- `extQ` (T.toJSON :: T LT.Text)- `extQ` (T.toJSON :: T String)- `extQ` (T.toJSON :: T T.Value)- `extQ` (T.toJSON :: T DotNetTime)- `extQ` (T.toJSON :: T UTCTime)- `extQ` (T.toJSON :: T IntSet)- `extQ` (T.toJSON :: T Bool)- `extQ` (T.toJSON :: T ())- --`extQ` (T.toJSON :: T Ordering)- where- list xs = Array . V.fromList . map toJSON $ xs- vector v = Array . V.map toJSON $ v- set s = Array . V.fromList . map toJSON . Set.toList $ s-- mapAny m- | tyrep == typeOf DT.empty = remap id- | tyrep == typeOf LT.empty = remap LT.toStrict- | tyrep == typeOf "" = remap pack- | otherwise = modError "toJSON" $- "cannot convert map keyed by type " ++ show tyrep- where tyrep = typeOf . head . Map.keys $ m- remap f = Object . mapHashKeyVal (f . fromJust . cast) toJSON $ m-- hashMapAny m- | tyrep == typeOf DT.empty = remap id- | tyrep == typeOf LT.empty = remap LT.toStrict- | tyrep == typeOf "" = remap pack- | otherwise = modError "toJSON" $- "cannot convert map keyed by type " ++ show tyrep- where tyrep = typeOf . head . H.keys $ m- remap f = Object . mapKeyVal (f . fromJust . cast) toJSON $ m--toJSON_generic :: (Data a) => a -> Value-toJSON_generic = generic- where- -- Generic encoding of an algebraic data type.- generic a =- case dataTypeRep (dataTypeOf a) of- -- No constructor, so it must be an error value. Code- -- it anyway as Null.- AlgRep [] -> Null- -- Elide a single constructor and just code the arguments.- AlgRep [c] -> encodeArgs c (gmapQ toJSON a)- -- For multiple constructors, make an object with a- -- field name that is the constructor (except lower- -- case) and the data is the arguments encoded.- AlgRep _ -> encodeConstr (toConstr a) (gmapQ toJSON a)- rep -> err (dataTypeOf a) rep- where- err dt r = modError "toJSON" $ "not AlgRep " ++- show r ++ "(" ++ show dt ++ ")"- -- Encode nullary constructor as a string.- -- Encode non-nullary constructors as an object with the constructor- -- name as the single field and the arguments as the value.- -- Use an array if the are no field names, but elide singleton arrays,- -- and use an object if there are field names.- encodeConstr c [] = String . constrString $ c- encodeConstr c as = object [(constrString c, encodeArgs c as)]-- constrString = pack . showConstr-- encodeArgs c = encodeArgs' (constrFields c)- encodeArgs' [] [j] = j- encodeArgs' [] js = Array . V.fromList $ js- encodeArgs' ns js = object $ zip (map pack ns) js---fromJSON :: (Data a) => Value -> Result a-fromJSON = parse parseJSON--type F a = Parser a--parseJSON :: (Data a) => Value -> Parser a-parseJSON j = parseJSON_generic j- `ext1R` maybeP- `ext1R` list- `ext1R` vector- `ext2R'` mapAny- `ext2R'` hashMapAny- -- Use the standard encoding for all base types.- `extR` (value :: F Integer)- `extR` (value :: F Int)- `extR` (value :: F Int8)- `extR` (value :: F Int16)- `extR` (value :: F Int32)- `extR` (value :: F Int64)- `extR` (value :: F Word)- `extR` (value :: F Word8)- `extR` (value :: F Word16)- `extR` (value :: F Word32)- `extR` (value :: F Word64)- `extR` (value :: F Double)- `extR` (value :: F Number)- `extR` (value :: F Float)- `extR` (value :: F Rational)- `extR` (value :: F Char)- `extR` (value :: F Text)- `extR` (value :: F LT.Text)- `extR` (value :: F String)- `extR` (value :: F T.Value)- `extR` (value :: F DotNetTime)- `extR` (value :: F UTCTime)- `extR` (value :: F IntSet)- `extR` (value :: F Bool)- `extR` (value :: F ())- where- value :: (T.FromJSON a) => Parser a- value = T.parseJSON j- maybeP :: (Data a) => Parser (Maybe a)- maybeP = if j == Null then return Nothing else Just <$> parseJSON j- list :: (Data a) => Parser [a]- list = V.toList <$> parseJSON j- vector :: (Data a) => Parser (V.Vector a)- vector = case j of- Array js -> V.mapM parseJSON js- _ -> myFail-- mapAny :: forall e f. (Data e, Data f) => Parser (Map.Map f e)- mapAny- | tyrep == typeOf DT.empty = process id- | tyrep == typeOf LT.empty = process LT.fromStrict- | tyrep == typeOf "" = process DT.unpack- | otherwise = myFail- where- process f = maybe myFail return . cast =<< parseWith f- parseWith :: (Ord c) => (Text -> c) -> Parser (Map.Map c e)- parseWith f = case j of- Object js -> Map.fromList . map (first f) . H.toList <$>- T.mapM parseJSON js- _ -> myFail- tyrep = typeOf (undefined :: f)-- hashMapAny :: forall e f. (Data e, Data f) => Parser (H.HashMap f e)- hashMapAny- | tyrep == typeOf DT.empty = process id- | tyrep == typeOf LT.empty = process LT.fromStrict- | tyrep == typeOf "" = process DT.unpack- | otherwise = myFail- where- process f = maybe myFail return . cast =<< parseWith f- parseWith :: (Eq c, Hashable c) => (Text -> c) -> Parser (H.HashMap c e)- parseWith f = case j of- Object js -> mapKey f <$> T.mapM parseJSON js- _ -> myFail- tyrep = typeOf (undefined :: f)-- myFail = modFail "parseJSON" $ "bad data: " ++ show j--parseJSON_generic :: (Data a) => Value -> Parser a-parseJSON_generic j = generic- where- typ = dataTypeOf $ resType generic- generic = case dataTypeRep typ of- AlgRep [] -> case j of- Null -> return (modError "parseJSON" "empty type")- _ -> modFail "parseJSON" "no-constr bad data"- AlgRep [_] -> decodeArgs (indexConstr typ 1) j- AlgRep _ -> do (c, j') <- getConstr typ j; decodeArgs c j'- rep -> modFail "parseJSON" $- show rep ++ "(" ++ show typ ++ ")"- getConstr t (Object o) | [(s, j')] <- fromJSObject o = do- c <- readConstr' t s- return (c, j')- getConstr t (String js) = do c <- readConstr' t (unpack js)- return (c, Null) -- handle nullary ctor- getConstr _ _ = modFail "parseJSON" "bad constructor encoding"- readConstr' t s =- maybe (modFail "parseJSON" $ "unknown constructor: " ++ s ++ " " ++- show t)- return $ readConstr t s-- decodeArgs c0 = go (numConstrArgs (resType generic) c0) c0- (constrFields c0)- where- go 0 c _ Null = construct c []- go 1 c [] jd = construct c [jd] -- unary constructor- go _ c [] (Array js) = construct c (V.toList js) -- no field names- -- FIXME? We could allow reading an array into a constructor- -- with field names.- go _ c fs@(_:_) (Object o) = selectFields o fs >>=- construct c -- field names- go _ c _ jd = modFail "parseJSON" $- "bad decodeArgs data " ++ show (c, jd)-- fromJSObject = map (first unpack) . H.toList-- -- Build the value by stepping through the list of subparts.- construct c = evalStateT $ fromConstrM f c- where f :: (Data a) => StateT [Value] Parser a- f = do js <- get- case js of- [] -> lift $ modFail "construct" "empty list"- (j':js') -> do put js'; lift $ parseJSON j'-- -- Select the named fields from a JSON object.- selectFields fjs = mapM $ \f ->- maybe (modFail "parseJSON" $ "field does not exist " ++ f) return $- H.lookup (pack f) fjs-- -- Count how many arguments a constructor has. The value x is- -- used to determine what type the constructor returns.- numConstrArgs :: (Data a) => a -> Constr -> Int- numConstrArgs x c = execState (fromConstrM f c `asTypeOf` return x) 0- where f = do modify (+1); return undefined-- resType :: MonadPlus m => m a -> a- resType _ = modError "parseJSON" "resType"--modFail :: (Monad m) => String -> String -> m a-modFail func err = fail $ "Data.Aeson.Generic." ++ func ++ ": " ++ err--modError :: String -> String -> a-modError func err = error $ "Data.Aeson.Generic." ++ func ++ ": " ++ err----- Type extension for binary type constructors.---- | Flexible type extension-#if MIN_VERSION_base(4,7,0)-ext2' :: (Data a, Typeable t)-#else-ext2' :: (Data a, Typeable2 t)-#endif- => c a- -> (forall d1 d2. (Data d1, Data d2) => c (t d1 d2))- -> c a-ext2' def ext = maybe def id (dataCast2 ext)---- | Type extension of queries for type constructors-#if MIN_VERSION_base(4,7,0)-ext2Q' :: (Data d, Typeable t)-#else-ext2Q' :: (Data d, Typeable2 t)-#endif- => (d -> q)- -> (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q)- -> d -> q-ext2Q' def ext = unQ ((Q def) `ext2'` (Q ext))---- | Type extension of readers for type constructors-#if MIN_VERSION_base(4,7,0)-ext2R' :: (Monad m, Data d, Typeable t)-#else-ext2R' :: (Monad m, Data d, Typeable2 t)-#endif- => m d- -> (forall d1 d2. (Data d1, Data d2) => m (t d1 d2))- -> m d-ext2R' def ext = unR ((R def) `ext2'` (R ext))---- | The type constructor for queries-newtype Q q x = Q { unQ :: x -> q }---- | The type constructor for readers-newtype R m x = R { unR :: m x }
+ Data/Aeson/Internal.hs view
@@ -0,0 +1,25 @@+-- |+-- Module: Data.Aeson.Internal+-- Copyright: (c) 2015 Bryan O'Sullivan+-- License: Apache+-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>+-- Stability: experimental+-- Portability: portable+--+-- Internal types and functions.+--+-- __Note__: all declarations in this module are unstable, and prone+-- to being changed at any time.++module Data.Aeson.Internal+ (+ IResult(..)+ , JSONPathElement+ , JSONPath+ , formatError+ , ifromJSON+ , iparse+ ) where++import Data.Aeson.Types.Instances (ifromJSON)+import Data.Aeson.Types.Internal
+ Data/Aeson/Internal/Time.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE CPP #-}++-- |+-- Module: Data.Aeson.Internal.Time+-- Copyright: (c) 2015 Bryan O'Sullivan+-- License: Apache+-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>+-- Stability: experimental+-- Portability: portable++module Data.Aeson.Internal.Time+ (+ TimeOfDay64(..)+ , fromPico+ , toPico+ , diffTimeOfDay64+ , toTimeOfDay64+ ) where++import Data.Fixed (Pico)+import Data.Int (Int64)+import Data.Time+import Unsafe.Coerce (unsafeCoerce)++#if MIN_VERSION_base(4,7,0)++import Data.Fixed (Fixed(MkFixed))++toPico :: Integer -> Pico+toPico = MkFixed++fromPico :: Pico -> Integer+fromPico (MkFixed i) = i++#else++toPico :: Integer -> Pico+toPico = unsafeCoerce++fromPico :: Pico -> Integer+fromPico = unsafeCoerce++#endif++-- | Like TimeOfDay, but using a fixed-width integer for seconds.+data TimeOfDay64 = TOD {-# UNPACK #-} !Int+ {-# UNPACK #-} !Int+ {-# UNPACK #-} !Int64++diffTimeOfDay64 :: DiffTime -> TimeOfDay64+diffTimeOfDay64 t = TOD (fromIntegral h) (fromIntegral m) s+ where (h,mp) = fromIntegral pico `quotRem` 3600000000000000+ (m,s) = mp `quotRem` 60000000000000+ pico = unsafeCoerce t :: Integer++toTimeOfDay64 :: TimeOfDay -> TimeOfDay64+toTimeOfDay64 (TimeOfDay h m s) = TOD h m (fromIntegral (fromPico s))
Data/Aeson/Parser.hs view
@@ -2,7 +2,7 @@ -- | -- Module: Data.Aeson.Parser--- Copyright: (c) 2012 Bryan O'Sullivan+-- Copyright: (c) 2012-2015 Bryan O'Sullivan -- (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Bryan O'Sullivan <bos@serpentine.com>
Data/Aeson/Parser/Internal.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE BangPatterns, CPP, OverloadedStrings #-}+#if MIN_VERSION_ghc_prim(0,3,1)+{-# LANGUAGE MagicHash #-}+#endif -- | -- Module: Data.Aeson.Parser.Internal--- Copyright: (c) 2011, 2012 Bryan O'Sullivan+-- Copyright: (c) 2011-2015 Bryan O'Sullivan -- (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Bryan O'Sullivan <bos@serpentine.com>@@ -28,9 +31,9 @@ , eitherDecodeStrictWith ) where -import Control.Applicative ((*>), (<$>), (<*), liftA2, pure)+import Control.Applicative ((*>), (<$>), (<*), pure) import Control.Monad.IO.Class (liftIO)-import Data.Aeson.Types (Result(..), Value(..))+import Data.Aeson.Types.Internal (IResult(..), JSONPath, Result(..), Value(..)) import Data.Attoparsec.ByteString.Char8 (Parser, char, endOfInput, scientific, skipSpace, string) import Data.Bits ((.|.), shiftL)@@ -40,22 +43,27 @@ import Data.Text.Encoding (decodeUtf8') import Data.Text.Internal.Encoding.Utf8 (ord2, ord3, ord4) import Data.Text.Internal.Unsafe.Char (ord)-import Data.Vector as Vector (Vector, fromList)+import Data.Vector as Vector (Vector, empty, fromList, reverse) import Data.Word (Word8) import Foreign.ForeignPtr (withForeignPtr)-import Foreign.Ptr (minusPtr) import Foreign.Ptr (Ptr, plusPtr)+import Foreign.Ptr (minusPtr) import Foreign.Storable (poke) import System.IO.Unsafe (unsafePerformIO) import qualified Data.Attoparsec.ByteString as A import qualified Data.Attoparsec.Lazy as L import qualified Data.Attoparsec.Zepto as Z import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Internal as B+import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Unsafe as B import qualified Data.HashMap.Strict as H +#if MIN_VERSION_ghc_prim(0,3,1)+import GHC.Base (Int#, (==#), isTrue#, orI#, word2Int#)+import GHC.Word (Word8(W8#))+#endif+ #define BACKSLASH 92 #define CLOSE_CURLY 125 #define CLOSE_SQUARE 93@@ -112,8 +120,19 @@ objectValues :: Parser Text -> Parser Value -> Parser (H.HashMap Text Value) objectValues str val = do skipSpace- let pair = liftA2 (,) (str <* skipSpace) (char ':' *> val)- H.fromList <$> commaSeparated pair CLOSE_CURLY+ w <- A.peekWord8'+ if w == CLOSE_CURLY+ then A.anyWord8 >> return H.empty+ else loop H.empty+ where+ loop m0 = do+ k <- str <* skipSpace <* char ':'+ v <- val <* skipSpace+ let !m = H.insert k v m0+ ch <- A.satisfy $ \w -> w == COMMA || w == CLOSE_CURLY+ if ch == COMMA+ then skipSpace >> loop m+ else return m {-# INLINE objectValues #-} array_ :: Parser Value@@ -124,25 +143,20 @@ !vals <- arrayValues value' return (Array vals) -commaSeparated :: Parser a -> Word8 -> Parser [a]-commaSeparated item endByte = do- w <- A.peekWord8'- if w == endByte- then A.anyWord8 >> return []- else loop- where- loop = do- v <- item <* skipSpace- ch <- A.satisfy $ \w -> w == COMMA || w == endByte- if ch == COMMA- then skipSpace >> (v:) <$> loop- else return [v]-{-# INLINE commaSeparated #-}- arrayValues :: Parser Value -> Parser (Vector Value) arrayValues val = do skipSpace- Vector.fromList <$> commaSeparated val CLOSE_SQUARE+ w <- A.peekWord8'+ if w == CLOSE_SQUARE+ then A.anyWord8 >> return Vector.empty+ else loop []+ where+ loop acc = do+ v <- val <* skipSpace+ ch <- A.satisfy $ \w -> w == COMMA || w == CLOSE_SQUARE+ if ch == COMMA+ then skipSpace >> loop (v:acc)+ else return (Vector.reverse (Vector.fromList (v:acc))) {-# INLINE arrayValues #-} -- | Parse any JSON value. You should usually 'json' in preference to@@ -196,24 +210,42 @@ -- | Parse a string without a leading quote. jstring_ :: Parser Text+{-# INLINE jstring_ #-} jstring_ = {-# SCC "jstring_" #-} do- s <- A.scan False $ \s c -> if s then Just False- else if c == DOUBLE_QUOTE- then Nothing- else Just (c == BACKSLASH)- _ <- A.word8 DOUBLE_QUOTE- s1 <- if BACKSLASH `B.elem` s+ (s, fin) <- A.runScanner startState go+ _ <- A.anyWord8+ s1 <- if isEscaped fin then case unescape s of- Right r -> return r- Left err -> fail err- else return s-+ Right r -> return r+ Left err -> fail err+ else return s case decodeUtf8' s1 of- Right r -> return r- Left err -> fail $ show err+ Right r -> return r+ Left err -> fail $ show err+ where+#if MIN_VERSION_ghc_prim(0,3,1)+ isEscaped (S _ escaped) = isTrue# escaped+ startState = S 0# 0#+ go (S a b) (W8# c)+ | isTrue# a = Just (S 0# b)+ | isTrue# (word2Int# c ==# 34#) = Nothing -- double quote+ | otherwise = let a' = word2Int# c ==# 92# -- backslash+ in Just (S a' (orI# a' b)) -{-# INLINE jstring_ #-}+data S = S Int# Int#+#else+ isEscaped (S _ escaped) = escaped+ startState = S False False+ go (S a b) c+ | a = Just (S False b)+ | c == DOUBLE_QUOTE = Nothing+ | otherwise = let a' = c == backslash+ in Just (S a' (a' || b))+ where backslash = BACKSLASH +data S = S !Bool !Bool+#endif+ unescape :: ByteString -> Either String ByteString unescape s = unsafePerformIO $ do let len = B.length s@@ -289,25 +321,25 @@ decodeStrictWith p to s = case either Error to (A.parseOnly p s) of Success a -> Just a- Error _ -> Nothing+ _ -> Nothing {-# INLINE decodeStrictWith #-} -eitherDecodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString- -> Either String a+eitherDecodeWith :: Parser Value -> (Value -> IResult a) -> L.ByteString+ -> Either (JSONPath, String) a eitherDecodeWith p to s = case L.parse p s of- L.Done _ v -> case to v of- Success a -> Right a- Error msg -> Left msg- L.Fail _ _ msg -> Left msg+ L.Done _ v -> case to v of+ ISuccess a -> Right a+ IError path msg -> Left (path, msg)+ L.Fail _ _ msg -> Left ([], msg) {-# INLINE eitherDecodeWith #-} -eitherDecodeStrictWith :: Parser Value -> (Value -> Result a) -> B.ByteString- -> Either String a+eitherDecodeStrictWith :: Parser Value -> (Value -> IResult a) -> B.ByteString+ -> Either (JSONPath, String) a eitherDecodeStrictWith p to s =- case either Error to (A.parseOnly p s) of- Success a -> Right a- Error msg -> Left msg+ case either (IError []) to (A.parseOnly p s) of+ ISuccess a -> Right a+ IError path msg -> Left (path, msg) {-# INLINE eitherDecodeStrictWith #-} -- $lazy
+ Data/Aeson/Parser/Time.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}++-- |+-- Module: Data.Aeson.Parser.Time+-- Copyright: (c) 2015 Bryan O'Sullivan+-- License: Apache+-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>+-- Stability: experimental+-- Portability: portable+--+-- Parsers for parsing dates and times.++module Data.Aeson.Parser.Time+ (+ run+ , day+ , localTime+ , timeOfDay+ , timeZone+ , utcTime+ , zonedTime+ ) where++import Control.Applicative ((<$>), (<*>), (<*), (*>))+import Control.Monad (when, void)+import Data.Aeson.Internal.Time (toPico)+import Data.Attoparsec.Text as A+import Data.Bits ((.&.))+import Data.Char (isDigit, ord)+import Data.Fixed (Pico)+import Data.Int (Int64)+import Data.Maybe (fromMaybe)+import Data.Text (Text)+import Data.Time.Calendar (Day, fromGregorianValid)+import Data.Time.Clock (UTCTime(..))+import qualified Data.Aeson.Types.Internal as Aeson+import qualified Data.Text as T+import qualified Data.Time.LocalTime as Local++-- | Run an attoparsec parser as an aeson parser.+run :: Parser a -> Text -> Aeson.Parser a+run p t = case A.parseOnly (p <* endOfInput) t of+ Left err -> fail $ "could not parse date: " ++ err+ Right r -> return r++-- | Parse a date of the form @YYYY-MM-DD@.+day :: Parser Day+day = do+ y <- decimal <* char '-'+ m <- twoDigits <* char '-'+ d <- twoDigits+ maybe (fail "invalid date") return (fromGregorianValid y m d)++-- | Parse a two-digit integer (e.g. day of month, hour).+twoDigits :: Parser Int+twoDigits = do+ a <- digit+ b <- digit+ let c2d c = ord c .&. 15+ return $! c2d a * 10 + c2d b++-- | Parse a time of the form @HH:MM:SS[.SSS]@.+timeOfDay :: Parser Local.TimeOfDay+timeOfDay = do+ h <- twoDigits <* char ':'+ m <- twoDigits <* char ':'+ s <- seconds+ if h < 24 && m < 60 && s < 61+ then return (Local.TimeOfDay h m s)+ else fail "invalid time"++data T = T {-# UNPACK #-} !Int {-# UNPACK #-} !Int64++-- | Parse a count of seconds, with the integer part being two digits+-- long.+seconds :: Parser Pico+seconds = do+ real <- twoDigits+ mc <- peekChar+ case mc of+ Just '.' -> do+ t <- anyChar *> takeWhile1 isDigit+ return $! parsePicos real t+ _ -> return $! fromIntegral real+ where+ parsePicos a0 t = toPico (fromIntegral (t' * 10^n))+ where T n t' = T.foldl' step (T 12 (fromIntegral a0)) t+ step ma@(T m a) c+ | m <= 0 = ma+ | otherwise = T (m-1) (10 * a + fromIntegral (ord c) .&. 15)++-- | Parse a time zone, and return 'Nothing' if the offset from UTC is+-- zero. (This makes some speedups possible.)+timeZone :: Parser (Maybe Local.TimeZone)+timeZone = do+ let maybeSkip c = do ch <- peekChar'; when (ch == c) (void anyChar)+ maybeSkip ' '+ ch <- satisfy $ \c -> c == 'Z' || c == '+' || c == '-'+ if ch == 'Z'+ then return Nothing+ else do+ h <- twoDigits+ mm <- peekChar+ m <- case mm of+ Just ':' -> anyChar *> twoDigits+ Just d | isDigit d -> twoDigits+ _ -> return 0+ let off | ch == '-' = negate off0+ | otherwise = off0+ off0 = h * 60 + m+ case undefined of+ _ | off == 0 ->+ return Nothing+ | off < -720 || off > 840 || m > 59 ->+ fail "invalid time zone offset"+ | otherwise ->+ let !tz = Local.minutesToTimeZone off+ in return (Just tz)++-- | Parse a date and time, of the form @YYYY-MM-DD HH:MM:SS@.+-- The space may be replaced with a @T@. The number of seconds may be+-- followed by a fractional component.+localTime :: Parser Local.LocalTime+localTime = Local.LocalTime <$> day <* daySep <*> timeOfDay+ where daySep = satisfy (\c -> c == 'T' || c == ' ')++-- | Behaves as 'zonedTime', but converts any time zone offset into a+-- UTC time.+utcTime :: Parser UTCTime+utcTime = do+ lt@(Local.LocalTime d t) <- localTime+ mtz <- timeZone+ case mtz of+ Nothing -> let !tt = Local.timeOfDayToTime t+ in return (UTCTime d tt)+ Just tz -> return $! Local.localTimeToUTC tz lt++-- | Parse a date with time zone info. Acceptable formats:+--+-- @YYYY-MM-DD HH:MM:SS Z@+--+-- The first space may instead be a @T@, and the second space is+-- optional. The @Z@ represents UTC. The @Z@ may be replaced with a+-- time zone offset of the form @+0000@ or @-08:00@, where the first+-- two digits are hours, the @:@ is optional and the second two digits+-- (also optional) are minutes.+zonedTime :: Parser Local.ZonedTime+zonedTime = Local.ZonedTime <$> localTime <*> (fromMaybe utc <$> timeZone)++utc :: Local.TimeZone+utc = Local.TimeZone 0 False ""
Data/Aeson/TH.hs view
@@ -4,7 +4,7 @@ {-| Module: Data.Aeson.TH-Copyright: (c) 2011, 2012 Bryan O'Sullivan+Copyright: (c) 2011-2015 Bryan O'Sullivan (c) 2011 MailRank, Inc. License: Apache Stability: experimental@@ -49,6 +49,20 @@ >>> fromJSON (toJSON d) == Success d > True +This also works for data family instances, but instead of passing in the data+family name (with double quotes), we pass in a data family instance+constructor (with a single quote):++@+data family DF a+data instance DF Int = DF1 Int+ | DF2 Int Int+ deriving Eq++$('deriveJSON' 'defaultOptions' 'DF1)+-- Alternatively, one could pass 'DF2 instead+@+ Please note that you can derive instances for tuples using the following syntax: @@@ -69,16 +83,14 @@ , deriveFromJSON , mkToJSON+ , mkToEncoding , mkParseJSON ) where ------------------------------------------------------------------------------------ Imports------------------------------------------------------------------------------------- from aeson:-import Data.Aeson ( toJSON, Object, object, (.=), (.:), (.:?)- , ToJSON, toJSON+import Control.Applicative ( pure, (<$>), (<*>) )+import Control.Monad ( return, mapM, liftM2, fail )+import Data.Aeson ( toJSON, Object, (.=), (.:), (.:?)+ , ToJSON, toEncoding, toJSON , FromJSON, parseJSON ) import Data.Aeson.Types ( Value(..), Parser@@ -87,30 +99,38 @@ , defaultOptions , defaultTaggedObject )--- from base:-import Control.Applicative ( pure, (<$>), (<*>) )-import Control.Monad ( return, mapM, liftM2, fail )-import Data.Bool ( Bool(False, True), otherwise, (&&) )+import Data.Aeson.Types.Internal (Encoding(..))+import Control.Monad ( return, mapM, liftM2, fail, join )+import Data.Bool ( Bool(False, True), otherwise, (&&), not )+import Data.Either ( Either(Left, Right) ) import Data.Eq ( (==) )-import Data.Function ( ($), (.) )+import Data.Function ( ($), (.), flip ) import Data.Functor ( fmap ) import Data.Int ( Int )-import Data.Either ( Either(Left, Right) )-import Data.List ( (++), foldl, foldl', intercalate- , length, map, zip, genericLength, all, partition+import Data.List ( (++), all, any, filter, find, foldl, foldl'+ , genericLength , intercalate , intersperse, length, map+ , partition, zip ) import Data.Maybe ( Maybe(Nothing, Just), catMaybes )-import Prelude ( String, (-), Integer, fromIntegral, error )+import Data.Monoid ( (<>), mconcat )+import Language.Haskell.TH+import Language.Haskell.TH.Syntax ( VarStrictType )+import Prelude ( String, (-), Integer, error, foldr1, fromIntegral+ , snd, uncurry+ )+#if MIN_VERSION_template_haskell(2,8,0) && __GLASGOW_HASKELL__ < 710+import Prelude ( drop )+#endif import Text.Printf ( printf ) import Text.Show ( show )--- from unordered-containers:+import qualified Data.Aeson as A+import qualified Data.Aeson.Encode.Builder as E+import qualified Data.Aeson.Encode.Functions as E import qualified Data.HashMap.Strict as H ( lookup, toList )--- from template-haskell:-import Language.Haskell.TH-import Language.Haskell.TH.Syntax ( VarStrictType )--- from text:+#if MIN_VERSION_template_haskell(2,8,0) && __GLASGOW_HASKELL__ < 710+import qualified Data.Set as Set ( Set, empty, singleton, size, union, unions )+#endif import qualified Data.Text as T ( Text, pack, unpack )--- from vector: import qualified Data.Vector as V ( unsafeIndex, null, length, create, fromList ) import qualified Data.Vector.Mutable as VM ( unsafeNew, unsafeWrite ) @@ -120,7 +140,7 @@ -------------------------------------------------------------------------------- -- | Generates both 'ToJSON' and 'FromJSON' instance declarations for the given--- data type.+-- data type or data family instance constructor. -- -- This is a convienience function which is equivalent to calling both -- 'deriveToJSON' and 'deriveFromJSON'.@@ -149,7 +169,8 @@ The above (ToJSON a) constraint is not necessary and perhaps undesirable. -} --- | Generates a 'ToJSON' instance declaration for the given data type.+-- | Generates a 'ToJSON' instance declaration for the given data type or+-- data family instance constructor. deriveToJSON :: Options -- ^ Encoding options. -> Name@@ -157,48 +178,60 @@ -- declaration. -> Q [Dec] deriveToJSON opts name =- withType name $ \tvbs cons -> fmap (:[]) $ fromCons tvbs cons+ withType name $ \name' tvbs cons mbTys -> fmap (:[]) $ fromCons name' tvbs cons mbTys where- fromCons :: [TyVarBndr] -> [Con] -> Q Dec- fromCons tvbs cons =- instanceD (applyCon ''ToJSON typeNames)- (classType `appT` instanceType)+ fromCons :: Name -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Dec+ fromCons name' tvbs cons mbTys =+ instanceD instanceCxt+ instanceType [ funD 'toJSON [ clause []- (normalB $ consToJSON opts cons)+ (normalB $ consToValue opts cons) [] ]+ , funD 'toEncoding+ [ clause []+ (normalB $ consToEncoding opts cons)+ []+ ] ] where- classType = conT ''ToJSON- typeNames = map tvbName tvbs- instanceType = foldl' appT (conT name) $ map varT typeNames+ (instanceCxt, instanceType) =+ buildTypeInstance name' ''ToJSON tvbs mbTys --- | Generates a lambda expression which encodes the given data type as JSON.+-- | Generates a lambda expression which encodes the given data type or+-- data family instance constructor as a 'Value'. mkToJSON :: Options -- ^ Encoding options. -> Name -- ^ Name of the type to encode. -> Q Exp-mkToJSON opts name = withType name (\_ cons -> consToJSON opts cons)+mkToJSON opts name = withType name (\_ _ cons _ -> consToValue opts cons) --- | Helper function used by both 'deriveToJSON' and 'mkToJSON'. Generates code--- to generate the JSON encoding of a number of constructors. All constructors+-- | Generates a lambda expression which encodes the given data type or+-- data family instance constructor as a JSON string.+mkToEncoding :: Options -- ^ Encoding options.+ -> Name -- ^ Name of the type to encode.+ -> Q Exp+mkToEncoding opts name = withType name (\_ _ cons _ -> consToEncoding opts cons)++-- | Helper function used by both 'deriveToJSON' and 'mkToJSON'. Generates+-- code to generate a 'Value' of a number of constructors. All constructors -- must be from the same type.-consToJSON :: Options+consToValue :: Options -- ^ Encoding options. -> [Con] -- ^ Constructors for which to generate JSON generating code. -> Q Exp -consToJSON _ [] = error $ "Data.Aeson.TH.consToJSON: "+consToValue _ [] = error $ "Data.Aeson.TH.consToValue: " ++ "Not a single constructor given!" -- A single constructor is directly encoded. The constructor itself may be -- forgotten.-consToJSON opts [con] = do+consToValue opts [con] = do value <- newName "value"- lam1E (varP value) $ caseE (varE value) [encodeArgs opts False con]+ lam1E (varP value) $ caseE (varE value) [argsToValue opts False con] -consToJSON opts cons = do+consToValue opts cons = do value <- newName "value" lam1E (varP value) $ caseE (varE value) matches where@@ -208,7 +241,7 @@ | con <- cons , let conName = getConName con ]- | otherwise = [encodeArgs opts True con | con <- cons]+ | otherwise = [argsToValue opts True con | con <- cons] conStr :: Options -> Name -> Q Exp conStr opts = appE [|String|] . conTxt opts@@ -219,41 +252,77 @@ conStringE :: Options -> Name -> Q Exp conStringE opts = stringE . constructorTagModifier opts . nameBase +-- | Helper function used by both 'deriveToJSON' and 'mkToEncoding'. Generates+-- code to write out a value for a number of constructors. All constructors+-- must be from the same type.+consToEncoding :: Options+ -- ^ Encoding options.+ -> [Con]+ -- ^ Constructors for which to generate JSON generating code.+ -> Q Exp++consToEncoding _ [] = error $ "Data.Aeson.TH.consToEncoding: "+ ++ "Not a single constructor given!"++-- A single constructor is directly encoded. The constructor itself may be+-- forgotten.+consToEncoding opts [con] = do+ value <- newName "value"+ lam1E (varP value) $ caseE (varE value) [argsToEncoding opts False con]++-- Encode just the name of the constructor of a sum type iff all the+-- constructors are nullary.+consToEncoding opts cons = do+ value <- newName "value"+ lam1E (varP value) $ caseE (varE value) matches+ where+ matches+ | allNullaryToStringTag opts && all isNullary cons =+ [ match (conP conName [])+ (normalB $ [|Encoding|] `appE` encStr opts conName) []+ | con <- cons+ , let conName = getConName con+ ]+ | otherwise = [argsToEncoding opts True con | con <- cons]++encStr :: Options -> Name -> Q Exp+encStr opts = appE [|E.text|] . conTxt opts+ -- | If constructor is nullary. isNullary :: Con -> Bool isNullary (NormalC _ []) = True isNullary _ = False -encodeSum :: Options -> Bool -> Name -> Q Exp -> Q Exp-encodeSum opts multiCons conName exp+sumToValue :: Options -> Bool -> Name -> Q Exp -> Q Exp+sumToValue opts multiCons conName exp | multiCons = case sumEncoding opts of TwoElemArray -> [|Array|] `appE` ([|V.fromList|] `appE` listE [conStr opts conName, exp]) TaggedObject{tagFieldName, contentsFieldName} ->- [|object|] `appE` listE+ [|A.object|] `appE` listE [ infixApp [|T.pack tagFieldName|] [|(.=)|] (conStr opts conName) , infixApp [|T.pack contentsFieldName|] [|(.=)|] exp ] ObjectWithSingleField ->- [|object|] `appE` listE+ [|A.object|] `appE` listE [ infixApp (conTxt opts conName) [|(.=)|] exp ] | otherwise = exp -- | Generates code to generate the JSON encoding of a single constructor.-encodeArgs :: Options -> Bool -> Con -> Q Match+argsToValue :: Options -> Bool -> Con -> Q Match -- Nullary constructors. Generates code that explicitly matches against the -- constructor even though it doesn't contain data. This is useful to prevent -- type errors.-encodeArgs opts multiCons (NormalC conName []) =+argsToValue opts multiCons (NormalC conName []) = match (conP conName [])- (normalB (encodeSum opts multiCons conName [e|toJSON ([] :: [()])|]))+ (normalB (sumToValue opts multiCons conName [e|toJSON ([] :: [()])|])) [] -- Polyadic constructors with special case for unary constructors.-encodeArgs opts multiCons (NormalC conName ts) = do+argsToValue opts multiCons (NormalC conName ts) = do let len = length ts args <- mapM newName ["arg" ++ show n | n <- [1..len]] js <- case [[|toJSON|] `appE` varE arg | arg <- args] of@@ -277,13 +346,15 @@ (varE 'V.create `appE` doE (newMV:stmts++[ret])) match (conP conName $ map varP args)- (normalB $ encodeSum opts multiCons conName js)+ (normalB $ sumToValue opts multiCons conName js) [] -- Records.-encodeArgs opts multiCons (RecC conName ts) = do+argsToValue opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of+ (True,True,[(_,st,ty)]) -> argsToValue opts multiCons (NormalC conName [(st,ty)])+ _ -> do args <- mapM newName ["arg" ++ show n | (_, n) <- zip ts [1 :: Integer ..]]- let exp = [|object|] `appE` pairs+ let exp = [|A.object|] `appE` pairs pairs | omitNothingFields opts = infixApp maybeFields [|(++)|]@@ -298,9 +369,6 @@ (maybes, rest) = partition isMaybe argCons - isMaybe (_, (_, _, AppT (ConT t) _)) = t == ''Maybe- isMaybe _ = False- maybeToPair (arg, (field, _, _)) = infixApp (infixE (Just $ toFieldName field) [|(.=)|]@@ -321,7 +389,7 @@ then case sumEncoding opts of TwoElemArray -> [|toJSON|] `appE` tupE [conStr opts conName, exp] TaggedObject{tagFieldName} ->- [|object|] `appE`+ [|A.object|] `appE` -- TODO: Maybe throw an error in case -- tagFieldName overwrites a field in pairs. infixApp (infixApp [|T.pack tagFieldName|]@@ -330,33 +398,163 @@ [|(:)|] pairs ObjectWithSingleField ->- [|object|] `appE` listE+ [|A.object|] `appE` listE [ infixApp (conTxt opts conName) [|(.=)|] exp ] else exp ) [] -- Infix constructors.-encodeArgs opts multiCons (InfixC _ conName _) = do+argsToValue opts multiCons (InfixC _ conName _) = do al <- newName "argL" ar <- newName "argR" match (infixP (varP al) conName (varP ar)) ( normalB- $ encodeSum opts multiCons conName+ $ sumToValue opts multiCons conName $ [|toJSON|] `appE` listE [ [|toJSON|] `appE` varE a | a <- [al,ar] ] ) [] -- Existentially quantified constructors.-encodeArgs opts multiCons (ForallC _ _ con) =- encodeArgs opts multiCons con+argsToValue opts multiCons (ForallC _ _ con) =+ argsToValue opts multiCons con +isMaybe :: (a, (b, c, Type)) -> Bool+isMaybe (_, (_, _, AppT (ConT t) _)) = t == ''Maybe+isMaybe _ = False +(<^>) :: ExpQ -> ExpQ -> ExpQ+(<^>) a b = infixApp a [|(<>)|] b+infixr 6 <^>++(<:>) :: ExpQ -> ExpQ -> ExpQ+(<:>) a b = a <^> [|E.char7 ':'|] <^> b+infixr 5 <:>++(<%>) :: ExpQ -> ExpQ -> ExpQ+(<%>) a b = a <^> [|E.char7 ','|] <^> b+infixr 4 <%>++array :: ExpQ -> ExpQ+array exp = [|Encoding|] `appE` ([|E.char7 '['|] <^> exp <^> [|E.char7 ']'|])++object :: ExpQ -> ExpQ+object exp = [|Encoding|] `appE` ([|E.char7 '{'|] <^> exp <^> [|E.char7 '}'|])++sumToEncoding :: Options -> Bool -> Name -> Q Exp -> Q Exp+sumToEncoding opts multiCons conName exp+ | multiCons =+ let fexp = [|fromEncoding|] `appE` exp in+ case sumEncoding opts of+ TwoElemArray ->+ array (encStr opts conName <%> fexp)+ TaggedObject{tagFieldName, contentsFieldName} ->+ object $+ ([|E.text (T.pack tagFieldName)|] <:> encStr opts conName) <%>+ ([|E.text (T.pack contentsFieldName)|] <:> fexp)+ ObjectWithSingleField ->+ object (encStr opts conName <:> fexp)++ | otherwise = exp++-- | Generates code to generate the JSON encoding of a single constructor.+argsToEncoding :: Options -> Bool -> Con -> Q Match+-- Nullary constructors. Generates code that explicitly matches against the+-- constructor even though it doesn't contain data. This is useful to prevent+-- type errors.+argsToEncoding opts multiCons (NormalC conName []) =+ match (conP conName [])+ (normalB (sumToEncoding opts multiCons conName [e|toEncoding ([] :: [()])|]))+ []++-- Polyadic constructors with special case for unary constructors.+argsToEncoding opts multiCons (NormalC conName ts) = do+ let len = length ts+ args <- mapM newName ["arg" ++ show n | n <- [1..len]]+ js <- case args of+ -- Single argument is directly converted.+ [e] -> return ([|toEncoding|] `appE` varE e)+ -- Multiple arguments are converted to a JSON array.+ es ->+ return (array (foldr1 (<%>) [[|E.builder|] `appE` varE x | x <- es]))+ match (conP conName $ map varP args)+ (normalB $ sumToEncoding opts multiCons conName js)+ []++-- Records.+argsToEncoding opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of+ (True,True,[(_,st,ty)]) -> argsToEncoding opts multiCons (NormalC conName [(st,ty)])+ _ -> do+ args <- mapM newName ["arg" ++ show n | (_, n) <- zip ts [1 :: Integer ..]]++ let exp = object objBody++ objBody = [|mconcat|] `appE`+ ([|intersperse (E.char7 ',')|] `appE` pairs)+ pairs | omitNothingFields opts = infixApp maybeFields+ [|(<>)|]+ restFields+ | otherwise = listE (map toPair argCons)++ argCons = zip args ts++ maybeFields = [|catMaybes|] `appE` listE (map maybeToPair maybes)++ restFields = listE (map toPair rest)++ (maybes, rest) = partition isMaybe argCons++ maybeToPair (arg, (field, _, _)) =+ infixApp (infixE (Just $ toFieldName field)+ [|(.=)|]+ Nothing)+ [|(<$>)|]+ (varE arg)++ toPair (arg, (field, _, _)) =+ toFieldName field <:> [|E.builder|] `appE` varE arg++ toFieldName field = [|E.text|] `appE`+ ([|T.pack|] `appE` fieldLabelExp opts field)++ match (conP conName $ map varP args)+ ( normalB+ $ if multiCons+ then case sumEncoding opts of+ TwoElemArray -> array $+ encStr opts conName <%> [|fromEncoding|] `appE` exp+ TaggedObject{tagFieldName} -> object $+ ([|E.text (T.pack tagFieldName)|] <:>+ encStr opts conName) <%>+ objBody+ ObjectWithSingleField -> object $+ encStr opts conName <:> [|fromEncoding|] `appE` exp+ else exp+ ) []++-- Infix constructors.+argsToEncoding opts multiCons (InfixC _ conName _) = do+ al <- newName "argL"+ ar <- newName "argR"+ match (infixP (varP al) conName (varP ar))+ ( normalB+ $ sumToEncoding opts multiCons conName+ $ [|toEncoding|] `appE` listE [ [|toJSON|] `appE` varE a+ | a <- [al,ar]+ ]+ )+ []+-- Existentially quantified constructors.+argsToEncoding opts multiCons (ForallC _ _ con) =+ argsToEncoding opts multiCons con++ -------------------------------------------------------------------------------- -- FromJSON -------------------------------------------------------------------------------- --- | Generates a 'FromJSON' instance declaration for the given data type.+-- | Generates a 'FromJSON' instance declaration for the given data type or+-- data family instance constructor. deriveFromJSON :: Options -- ^ Encoding options. -> Name@@ -364,30 +562,29 @@ -- declaration. -> Q [Dec] deriveFromJSON opts name =- withType name $ \tvbs cons -> fmap (:[]) $ fromCons tvbs cons+ withType name $ \name' tvbs cons mbTys -> fmap (:[]) $ fromCons name' tvbs cons mbTys where- fromCons :: [TyVarBndr] -> [Con] -> Q Dec- fromCons tvbs cons =- instanceD (applyCon ''FromJSON typeNames)- (classType `appT` instanceType)+ fromCons :: Name -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Dec+ fromCons name' tvbs cons mbTys =+ instanceD instanceCxt+ instanceType [ funD 'parseJSON [ clause []- (normalB $ consFromJSON name opts cons)+ (normalB $ consFromJSON name' opts cons) [] ] ] where- classType = conT ''FromJSON- typeNames = map tvbName tvbs- instanceType = foldl' appT (conT name) $ map varT typeNames+ (instanceCxt, instanceType) =+ buildTypeInstance name' ''FromJSON tvbs mbTys -- | Generates a lambda expression which parses the JSON encoding of the given--- data type.+-- data type or data family instance constructor. mkParseJSON :: Options -- ^ Encoding options. -> Name -- ^ Name of the encoded type. -> Q Exp mkParseJSON opts name =- withType name (\_ cons -> consFromJSON name opts cons)+ withType name (\name' _ cons _ -> consFromJSON name' opts cons) -- | Helper function used by both 'deriveFromJSON' and 'mkParseJSON'. Generates -- code to parse the JSON encoding of a number of constructors. All constructors@@ -664,7 +861,9 @@ -- Records. parseArgs tName opts (RecC conName ts) (Left (_, obj)) = parseRecord opts tName conName ts obj-parseArgs tName opts (RecC conName ts) (Right valName) = do+parseArgs tName opts (RecC conName ts) (Right valName) = case (unwrapUnaryRecords opts,ts) of+ (True,[(_,st,ty)])-> parseArgs tName opts (NormalC conName [(st,ty)]) (Right valName)+ _ -> do obj <- newName "recObj" caseE (varE valName) [ match (conP 'Object [varP obj]) (normalB $ parseRecord opts tName conName ts obj) []@@ -755,7 +954,7 @@ Just v -> parseJSON v instance (FromJSON a) => LookupField (Maybe a) where- lookupField _ _ = (.:?)+ lookupField _ _ obj key = join <$> obj .:? key unknownFieldFail :: String -> String -> String -> Parser fail unknownFieldFail tName rec key =@@ -802,7 +1001,7 @@ t (intercalate ", " cs) o parseTypeMismatch' :: String -> String -> String -> String -> Parser fail-parseTypeMismatch' tName conName expected actual =+parseTypeMismatch' conName tName expected actual = fail $ printf "When parsing the constructor %s of type %s expected %s but got %s." conName tName expected actual @@ -813,14 +1012,19 @@ -- | Boilerplate for top level splices. ----- The given 'Name' must be from a type constructor. Furthermore, the--- type constructor must be either a data type or a newtype. Any other--- value will result in an exception.+-- The given 'Name' must meet one of two criteria:+--+-- 1. It must be the name of a type constructor of a plain data type or newtype.+-- 2. It must be the name of a data family instance or newtype instance constructor.++-- Any other value will result in an exception. withType :: Name- -> ([TyVarBndr] -> [Con] -> Q a)+ -> (Name -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q a) -- ^ Function that generates the actual code. Will be applied- -- to the type variable binders and constructors extracted- -- from the given 'Name'.+ -- to the datatype/data family 'Name', type variable binders and+ -- constructors extracted from the given 'Name'. If the 'Name' is+ -- from a data family instance constructor, it will also have its+ -- instantiated types; otherwise, it will be 'Nothing'. -> Q a -- ^ Resulting value in the 'Q'uasi monad. withType name f = do@@ -828,12 +1032,139 @@ case info of TyConI dec -> case dec of- DataD _ _ tvbs cons _ -> f tvbs cons- NewtypeD _ _ tvbs con _ -> f tvbs [con]- other -> error $ "Data.Aeson.TH.withType: Unsupported type: "- ++ show other- _ -> error "Data.Aeson.TH.withType: I need the name of a type."+ DataD _ _ tvbs cons _ -> f name tvbs cons Nothing+ NewtypeD _ _ tvbs con _ -> f name tvbs [con] Nothing+ other -> error $ ns ++ "Unsupported type: " ++ show other+#if MIN_VERSION_template_haskell(2,11,0)+ DataConI _ _ parentName -> do+#else+ DataConI _ _ parentName _ -> do+#endif+ parentInfo <- reify parentName+ case parentInfo of+#if MIN_VERSION_template_haskell(2,11,0)+ FamilyI (DataFamilyD _ tvbs _) decs ->+#else+ FamilyI (FamilyD DataFam _ tvbs _) decs ->+#endif+ let instDec = flip find decs $ \dec -> case dec of+ DataInstD _ _ _ cons _ -> any ((name ==) . getConName) cons+ NewtypeInstD _ _ _ con _ -> name == getConName con+ _ -> error $ ns ++ "Must be a data or newtype instance."+ in case instDec of+ Just (DataInstD _ _ instTys cons _)+ -> f parentName tvbs cons $ Just instTys+ Just (NewtypeInstD _ _ instTys con _)+ -> f parentName tvbs [con] $ Just instTys+ _ -> error $ ns +++ "Could not find data or newtype instance constructor."+ _ -> error $ ns ++ "Data constructor " ++ show name +++ " is not from a data family instance constructor."+#if MIN_VERSION_template_haskell(2,11,0)+ FamilyI DataFamilyD{} _ ->+#else+ FamilyI (FamilyD DataFam _ _ _) _ ->+#endif+ error $ ns +++ "Cannot use a data family name. Use a data family instance constructor instead."+ _ -> error $ ns ++ "I need the name of a plain data type constructor, "+ ++ "or a data family instance constructor."+ where+ ns :: String+ ns = "Data.Aeson.TH.withType: " +-- | Infer the context and instance head needed for a FromJSON or ToJSON instance.+buildTypeInstance :: Name+ -- ^ The type constructor or data family name+ -> Name+ -- ^ The typeclass name ('ToJSON' or 'FromJSON')+ -> [TyVarBndr]+ -- ^ The type variables from the data type/data family declaration+ -> Maybe [Type]+ -- ^ 'Just' the types used to instantiate a data family instance,+ -- or 'Nothing' if it's a plain data type+ -> (Q Cxt, Q Type)+ -- ^ The resulting 'Cxt' and 'Type' to use in a class instance+-- Plain data type/newtype case+buildTypeInstance tyConName constraint tvbs Nothing =+ (applyCon constraint typeNames, conT constraint `appT` instanceType)+ where+ typeNames :: [Name]+ typeNames = map tvbName tvbs++ instanceType :: Q Type+ instanceType = applyTyCon tyConName $ map varT typeNames+-- Data family instance case+buildTypeInstance dataFamName constraint tvbs (Just instTysAndKinds) =+ (applyCon constraint lhsTvbNames, conT constraint `appT` instanceType)+ where+ -- We need to make sure that type variables in the instance head which have+ -- constraints aren't poly-kinded, e.g.,+ --+ -- @+ -- instance ToJSON a => ToJSON (Foo (a :: k)) where+ -- @+ --+ -- To do this, we remove every kind ascription (i.e., strip off every 'SigT').+ instanceType :: Q Type+ instanceType = applyTyCon dataFamName $ map (return . unSigT) rhsTypes++ -- We need to mindful of an old GHC bug which causes kind variables appear in+ -- @instTysAndKinds@ (as the name suggests) if (1) @PolyKinds@ is enabled, and+ -- (2) either GHC 7.6 or 7.8 is being used (for more info, see+ -- https://ghc.haskell.org/trac/ghc/ticket/9692).+ --+ -- Since Template Haskell doesn't seem to have a mechanism for detecting which+ -- language extensions are enabled, we do the next-best thing by counting+ -- the number of distinct kind variables in the data family declaration, and+ -- then dropping that number of entries from @instTysAndKinds@+ instTypes :: [Type]+ instTypes =+#if __GLASGOW_HASKELL__ >= 710 || !(MIN_VERSION_template_haskell(2,8,0))+ instTysAndKinds+#else+ drop (Set.size . Set.unions $ map (distinctKindVars . tvbKind) tvbs)+ instTysAndKinds+#endif++ lhsTvbNames :: [Name]+ lhsTvbNames = map (tvbName . uncurry replaceTyVarName)+ . filter (isTyVar . snd)+ $ zip tvbs rhsTypes++ -- In GHC 7.8, only the @Type@s up to the rightmost non-eta-reduced type variable+ -- in @instTypes@ are provided (as a result of this bug:+ -- https://ghc.haskell.org/trac/ghc/ticket/9692). To work around this, we borrow+ -- some type variables from the data family instance declaration.+ rhsTypes :: [Type]+ rhsTypes =+#if __GLASGOW_HASKELL__ >= 708 && __GLASGOW_HASKELL__ < 710+ instTypes ++ map tvbToType+ (drop (length instTypes)+ tvbs)+#else+ instTypes+#endif++#if MIN_VERSION_template_haskell(2,8,0) && __GLASGOW_HASKELL__ < 710+distinctKindVars :: Kind -> Set.Set Name+distinctKindVars (AppT k1 k2) = distinctKindVars k1 `Set.union` distinctKindVars k2+distinctKindVars (SigT k _) = distinctKindVars k+distinctKindVars (VarT k) = Set.singleton k+distinctKindVars _ = Set.empty++-- | Extracts the kind from a type variable binder.+tvbKind :: TyVarBndr -> Kind+tvbKind (PlainTV _ ) = starK+tvbKind (KindedTV _ k) = k+#endif++#if __GLASGOW_HASKELL__ >= 708 && __GLASGOW_HASKELL__ < 710+tvbToType :: TyVarBndr -> Type+tvbToType (PlainTV n) = VarT n+tvbToType (KindedTV n k) = SigT (VarT n) k+#endif+ -- | Extracts the name from a constructor. getConName :: Con -> Name getConName (NormalC name _) = name@@ -845,6 +1176,28 @@ tvbName :: TyVarBndr -> Name tvbName (PlainTV name ) = name tvbName (KindedTV name _) = name++-- | Replace the Name of a TyVarBndr with one from a Type (if the Type has a Name).+replaceTyVarName :: TyVarBndr -> Type -> TyVarBndr+replaceTyVarName tvb (SigT t _) = replaceTyVarName tvb t+replaceTyVarName (PlainTV _) (VarT n) = PlainTV n+replaceTyVarName (KindedTV _ k) (VarT n) = KindedTV n k+replaceTyVarName tvb _ = tvb++-- | Fully applies a type constructor to its type variables.+applyTyCon :: Name -> [Q Type] -> Q Type+applyTyCon = foldl' appT . conT++-- | Is the given type a variable?+isTyVar :: Type -> Bool+isTyVar (VarT _) = True+isTyVar (SigT t _) = isTyVar t+isTyVar _ = False++-- | Peel off a kind signature from a Type (if it has one).+unSigT :: Type -> Type+unSigT (SigT t _) = t+unSigT t = t -- | Makes a string literal expression from a constructor's name. conNameExp :: Options -> Con -> Q Exp
Data/Aeson/Types.hs view
@@ -1,8 +1,6 @@-{-# LANGUAGE CPP #-}- -- | -- Module: Data.Aeson.Types--- Copyright: (c) 2011, 2012 Bryan O'Sullivan+-- Copyright: (c) 2011-2015 Bryan O'Sullivan -- (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Bryan O'Sullivan <bos@serpentine.com>@@ -15,6 +13,9 @@ ( -- * Core JSON types Value(..)+ , Encoding+ , fromEncoding+ , Series , Array , emptyArray , Pair@@ -32,15 +33,15 @@ , parseEither , parseMaybe , ToJSON(..)+ , KeyValue(..) , modifyFailure -#ifdef GENERICS -- ** Generic JSON classes , GFromJSON(..) , GToJSON(..) , genericToJSON+ , genericToEncoding , genericParseJSON-#endif -- * Inspecting @'Value's@ , withObject@@ -50,8 +51,8 @@ , withScientific , withBool - -- * Constructors and accessors- , (.=)+ , pairs+ , foldable , (.:) , (.:?) , (.!=)@@ -61,13 +62,12 @@ , Options(..) , SumEncoding(..) , camelTo+ , camelTo2 , defaultOptions , defaultTaggedObject ) where +import Data.Aeson.Encode.Functions (foldable, pairs)+import Data.Aeson.Types.Generic () import Data.Aeson.Types.Instances import Data.Aeson.Types.Internal--#ifdef GENERICS-import Data.Aeson.Types.Generic ()-#endif
Data/Aeson/Types/Class.hs view
@@ -1,12 +1,8 @@-{-# LANGUAGE CPP, FlexibleContexts #-}--#ifdef GENERICS-{-# LANGUAGE DefaultSignatures #-}-#endif+{-# LANGUAGE CPP, DefaultSignatures, FlexibleContexts #-} -- | -- Module: Data.Aeson.Types.Class--- Copyright: (c) 2011-2013 Bryan O'Sullivan+-- Copyright: (c) 2011-2015 Bryan O'Sullivan -- (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Bryan O'Sullivan <bos@serpentine.com>@@ -17,119 +13,179 @@ module Data.Aeson.Types.Class (- -- * Type classes- -- ** Core JSON classes+ -- * Core JSON classes FromJSON(..) , ToJSON(..)-#ifdef GENERICS- -- ** Generic JSON classes+ -- * Generic JSON classes , GFromJSON(..) , GToJSON(..) , genericToJSON+ , genericToEncoding , genericParseJSON-#endif+ -- * Object key-value pairs+ , KeyValue(..)+ -- * Functions needed for documentation+ , typeMismatch ) where import Data.Aeson.Types.Internal--#ifdef GENERICS-import GHC.Generics+import Data.Text (Text)+import GHC.Generics (Generic, Rep, from, to)+import qualified Data.Aeson.Encode.Builder as E --- | Class of generic representation types ('Rep') that can be converted to JSON.+-- | Class of generic representation types ('Rep') that can be converted to+-- JSON. class GToJSON f where -- | This method (applied to 'defaultOptions') is used as the -- default generic implementation of 'toJSON'. gToJSON :: Options -> f a -> Value + -- | This method (applied to 'defaultOptions') can be used as the+ -- default generic implementation of 'toEncoding'.+ gToEncoding :: Options -> f a -> Encoding+ -- | Class of generic representation types ('Rep') that can be converted from JSON. class GFromJSON f where -- | This method (applied to 'defaultOptions') is used as the -- default generic implementation of 'parseJSON'. gParseJSON :: Options -> Value -> Parser (f a) --- | A configurable generic JSON encoder. This function applied to+-- | A configurable generic JSON creator. This function applied to -- 'defaultOptions' is used as the default for 'toJSON' when the type -- is an instance of 'Generic'. genericToJSON :: (Generic a, GToJSON (Rep a)) => Options -> a -> Value genericToJSON opts = gToJSON opts . from +-- | A configurable generic JSON encoder. This function applied to+-- 'defaultOptions' is used as the default for 'toEncoding' when the type+-- is an instance of 'Generic'.+genericToEncoding :: (Generic a, GToJSON (Rep a)) => Options -> a -> Encoding+genericToEncoding opts = gToEncoding opts . from+ -- | A configurable generic JSON decoder. This function applied to -- 'defaultOptions' is used as the default for 'parseJSON' when the -- type is an instance of 'Generic'. genericParseJSON :: (Generic a, GFromJSON (Rep a)) => Options -> Value -> Parser a genericParseJSON opts = fmap to . gParseJSON opts-#endif -- | A type that can be converted to JSON. -- -- An example type and instance: ----- @{-\# LANGUAGE OverloadedStrings #-}+-- @+-- \-- Allow ourselves to write 'Text' literals.+-- {-\# LANGUAGE OverloadedStrings #-} -- -- data Coord = Coord { x :: Double, y :: Double } -- -- instance ToJSON Coord where -- toJSON (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]--- @ ----- Note the use of the @OverloadedStrings@ language extension which enables--- 'Text' values to be written as string literals.+-- toEncoding (Coord x y) = 'pairs' (\"x\" '.=' x '<>' \"y\" '.=' y)+-- @ ----- Instead of manually writing your 'ToJSON' instance, there are three options+-- Instead of manually writing your 'ToJSON' instance, there are two options -- to do it automatically: ----- * "Data.Aeson.TH" provides template-haskell functions which will derive an--- instance at compile-time. The generated instance is optimized for your type+-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an+-- instance at compile time. The generated instance is optimized for your type -- so will probably be more efficient than the following two options: ----- * "Data.Aeson.Generic" provides a generic @toJSON@ function that accepts any--- type which is an instance of 'Data'.------ * If your compiler has support for the @DeriveGeneric@ and--- @DefaultSignatures@ language extensions (GHC 7.2 and newer),--- @toJSON@ will have a default generic implementation.+-- * The compiler can provide a default generic implementation for+-- 'toJSON'. ----- To use the latter option, simply add a @deriving 'Generic'@ clause to your--- datatype and declare a @ToJSON@ instance for your datatype without giving a--- definition for @toJSON@.+-- To use the second, simply add a @deriving 'Generic'@ clause to your+-- datatype and declare a 'ToJSON' instance for your datatype without giving+-- definitions for 'toJSON' or 'toEncoding'. ----- For example the previous example can be simplified to just:+-- For example, the previous example can be simplified to a more+-- minimal instance: ----- @{-\# LANGUAGE DeriveGeneric \#-}+-- @+-- {-\# LANGUAGE DeriveGeneric \#-} ----- import GHC.Generics+-- import "GHC.Generics" ----- data Coord = Coord { x :: Double, y :: Double } deriving Generic+-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic' ----- instance ToJSON Coord+-- instance ToJSON Coord where+-- toEncoding = 'genericToEncoding' 'defaultOptions' -- @ ----- Note that, instead of using @DefaultSignatures@, it's also possible--- to parameterize the generic encoding using 'genericToJSON' applied--- to your encoding/decoding 'Options':+-- Why do we provide an implementation for 'toEncoding' here? The+-- 'toEncoding' function is a relatively new addition to this class.+-- To allow users of older versions of this library to upgrade without+-- having to edit all of their instances or encounter surprising+-- incompatibilities, the default implementation of 'toEncoding' uses+-- 'toJSON'. This produces correct results, but since it performs an+-- intermediate conversion to a 'Value', it will be less efficient+-- than directly emitting an 'Encoding'. Our one-liner definition of+-- 'toEncoding' above bypasses the intermediate 'Value'. --+-- If @DefaultSignatures@ doesn't give exactly the results you want,+-- you can customize the generic encoding with only a tiny amount of+-- effort, using 'genericToJSON' and 'genericToEncoding' with your+-- preferred 'Options':+-- -- @ -- instance ToJSON Coord where--- toJSON = 'genericToJSON' 'defaultOptions'+-- toJSON = 'genericToJSON' 'defaultOptions'+-- toEncoding = 'genericToEncoding' 'defaultOptions' -- @ class ToJSON a where- toJSON :: a -> Value+ -- | Convert a Haskell value to a JSON-friendly intermediate type.+ toJSON :: a -> Value+ {-# MINIMAL toJSON #-} -#ifdef GENERICS default toJSON :: (Generic a, GToJSON (Rep a)) => a -> Value toJSON = genericToJSON defaultOptions-#endif + -- | Encode a Haskell value as JSON.+ --+ -- The default implementation of this method creates an+ -- intermediate 'Value' using 'toJSON'. This provides+ -- source-level compatibility for people upgrading from older+ -- versions of this library, but obviously offers no performance+ -- advantage.+ --+ -- To benefit from direct encoding, you /must/ provide an+ -- implementation for this method. The easiest way to do so is by+ -- having your types implement 'Generic' using the @DeriveGeneric@+ -- extension, and then have GHC generate a method body as follows.+ --+ -- @+ -- instance ToJSON Coord where+ -- toEncoding = 'genericToEncoding' 'defaultOptions'+ -- @++ toEncoding :: a -> Encoding+ toEncoding = Encoding . E.encodeToBuilder . toJSON+ {-# INLINE toEncoding #-}+ -- | A type that can be converted from JSON, with the possibility of -- failure. ----- When writing an instance, use 'empty', 'mzero', or 'fail' to make a--- conversion fail, e.g. if an 'Object' is missing a required key, or--- the value is of the wrong type.+-- In many cases, you can get the compiler to generate parsing code+-- for you (see below). To begin, let's cover writing an instance by+-- hand. --+-- There are various reasons a conversion could fail. For example, an+-- 'Object' could be missing a required key, an 'Array' could be of+-- the wrong size, or a value could be of an incompatible type.+--+-- The basic ways to signal a failed conversion are as follows:+--+-- * 'empty' and 'mzero' work, but are terse and uninformative+--+-- * 'fail' yields a custom error message+--+-- * 'typeMismatch' produces an informative message for cases when the+-- value encountered is not of the expected type+-- -- An example type and instance: -- -- @+-- \-- Allow ourselves to write 'Text' literals. -- {-\# LANGUAGE OverloadedStrings #-} -- -- data Coord = Coord { x :: Double, y :: Double }@@ -139,46 +195,41 @@ -- v '.:' \"x\" '<*>' -- v '.:' \"y\" ----- \-- A non-'Object' value is of the wrong type, so use 'mzero' to fail.--- parseJSON _ = 'mzero'+-- \-- We do not expect a non-'Object' value here.+-- \-- We could use 'mzero' to fail, but 'typeMismatch'+-- \-- gives a much more informative error message.+-- parseJSON invalid = 'typeMismatch' \"Coord\" invalid -- @ ----- Note the use of the @OverloadedStrings@ language extension which enables--- 'Text' values to be written as string literals.------ Instead of manually writing your 'FromJSON' instance, there are three options+-- Instead of manually writing your 'FromJSON' instance, there are two options -- to do it automatically: ----- * "Data.Aeson.TH" provides template-haskell functions which will derive an--- instance at compile-time. The generated instance is optimized for your type+-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an+-- instance at compile time. The generated instance is optimized for your type -- so will probably be more efficient than the following two options: ----- * "Data.Aeson.Generic" provides a generic @fromJSON@ function that parses to--- any type which is an instance of 'Data'.------ * If your compiler has support for the @DeriveGeneric@ and--- @DefaultSignatures@ language extensions, @parseJSON@ will have a default--- generic implementation.+-- * The compiler can provide a default generic implementation for+-- 'parseJSON'. ----- To use this, simply add a @deriving 'Generic'@ clause to your datatype and--- declare a @FromJSON@ instance for your datatype without giving a definition--- for @parseJSON@.+-- To use the second, simply add a @deriving 'Generic'@ clause to your+-- datatype and declare a 'FromJSON' instance for your datatype without giving+-- a definition for 'parseJSON'. ----- For example the previous example can be simplified to just:+-- For example, the previous example can be simplified to just: -- -- @ -- {-\# LANGUAGE DeriveGeneric \#-} ----- import GHC.Generics+-- import "GHC.Generics" ----- data Coord = Coord { x :: Double, y :: Double } deriving Generic+-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic' -- -- instance FromJSON Coord -- @ ----- Note that, instead of using @DefaultSignatures@, it's also possible--- to parameterize the generic decoding using 'genericParseJSON' applied--- to your encoding/decoding 'Options':+-- If @DefaultSignatures@ doesn't give exactly the results you want,+-- you can customize the generic decoding with only a tiny amount of+-- effort, using 'genericParseJSON' with your preferred 'Options': -- -- @ -- instance FromJSON Coord where@@ -188,7 +239,33 @@ class FromJSON a where parseJSON :: Value -> Parser a -#ifdef GENERICS default parseJSON :: (Generic a, GFromJSON (Rep a)) => Value -> Parser a parseJSON = genericParseJSON defaultOptions-#endif++-- | A key-value pair for encoding a JSON object.+class KeyValue kv where+ (.=) :: ToJSON v => Text -> v -> kv+ infixr 8 .=++-- | Fail parsing due to a type mismatch, with a descriptive message.+--+-- Example usage:+--+-- @+-- instance FromJSON Coord where+-- parseJSON ('Object' v) = {- type matches, life is good -}+-- parseJSON wat = 'typeMismatch' \"Coord\" wat+-- @+typeMismatch :: String -- ^ The name of the type you are trying to parse.+ -> Value -- ^ The actual value encountered.+ -> Parser a+typeMismatch expected actual =+ fail $ "expected " ++ expected ++ ", encountered " ++ name+ where+ name = case actual of+ Object _ -> "Object"+ Array _ -> "Array"+ String _ -> "String"+ Number _ -> "Number"+ Bool _ -> "Boolean"+ Null -> "Null"
Data/Aeson/Types/Generic.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, DefaultSignatures, EmptyDataDecls, FlexibleInstances,+{-# LANGUAGE DefaultSignatures, EmptyDataDecls, FlexibleInstances, FunctionalDependencies, KindSignatures, OverlappingInstances, ScopedTypeVariables, TypeOperators, UndecidableInstances, ViewPatterns, NamedFieldPuns, FlexibleContexts, PatternGuards,@@ -7,7 +7,7 @@ -- | -- Module: Data.Aeson.Types.Generic--- Copyright: (c) 2012 Bryan O'Sullivan+-- Copyright: (c) 2012-2015 Bryan O'Sullivan -- (c) 2011, 2012 Bas Van Dijk -- (c) 2011 MailRank, Inc. -- License: Apache@@ -20,14 +20,17 @@ module Data.Aeson.Types.Generic ( ) where import Control.Applicative ((<*>), (<$>), (<|>), pure)-import Control.Monad ((<=<))+import Control.Monad ((<=<), join) import Control.Monad.ST (ST)+import Data.Aeson.Encode.Builder (emptyArray_)+import Data.Aeson.Encode.Functions (builder) import Data.Aeson.Types.Instances import Data.Aeson.Types.Internal-import Data.Bits+import Data.Bits (unsafeShiftR)+import Data.ByteString.Builder as B import Data.DList (DList, toList, empty) import Data.Maybe (fromMaybe)-import Data.Monoid (mappend)+import Data.Monoid ((<>), mempty) import Data.Text (Text, pack, unpack) import GHC.Generics import qualified Data.HashMap.Strict as H@@ -42,22 +45,34 @@ gToJSON opts = gToJSON opts . unM1 {-# INLINE gToJSON #-} + gToEncoding opts = gToEncoding opts . unM1+ {-# INLINE gToEncoding #-}+ instance (ToJSON a) => GToJSON (K1 i a) where -- Constant values are encoded using their ToJSON instance: gToJSON _opts = toJSON . unK1 {-# INLINE gToJSON #-} + gToEncoding _opts = toEncoding . unK1+ {-# INLINE gToEncoding #-}+ instance GToJSON U1 where -- Empty constructors are encoded to an empty array: gToJSON _opts _ = emptyArray {-# INLINE gToJSON #-} + gToEncoding _opts _ = emptyArray_+ {-# INLINE gToEncoding #-}+ instance (ConsToJSON a) => GToJSON (C1 c a) where -- Constructors need to be encoded differently depending on whether they're- -- a record or not. This distinction is made by 'constToJSON':+ -- a record or not. This distinction is made by 'consToJSON': gToJSON opts = consToJSON opts . unM1 {-# INLINE gToJSON #-} + gToEncoding opts = Encoding . consToEncoding opts . unM1+ {-# INLINE gToEncoding #-}+ instance ( WriteProduct a, WriteProduct b , ProductSize a, ProductSize b ) => GToJSON (a :*: b) where -- Products are encoded to an array. Here we allocate a mutable vector of@@ -73,6 +88,9 @@ productSize {-# INLINE gToJSON #-} + gToEncoding opts p = Encoding $+ B.char7 '[' <> encodeProduct opts p <> B.char7 ']'+ instance ( AllNullary (a :+: b) allNullary , SumToJSON (a :+: b) allNullary ) => GToJSON (a :+: b) where -- If all constructors of a sum datatype are nullary and the@@ -82,13 +100,19 @@ . sumToJSON opts {-# INLINE gToJSON #-} + gToEncoding opts = Encoding .+ (unTagged :: Tagged allNullary B.Builder -> B.Builder) .+ sumToEncoding opts+ {-# INLINE gToEncoding #-}+ -------------------------------------------------------------------------------- class SumToJSON f allNullary where sumToJSON :: Options -> f a -> Tagged allNullary Value+ sumToEncoding :: Options -> f a -> Tagged allNullary B.Builder instance ( GetConName f- , TaggedObject f+ , TaggedObject f , ObjectWithSingleField f , TwoElemArray f ) => SumToJSON f True where sumToJSON opts@@ -97,11 +121,19 @@ | otherwise = Tagged . nonAllNullarySumToJSON opts {-# INLINE sumToJSON #-} + sumToEncoding opts+ | allNullaryToStringTag opts = Tagged . builder .+ constructorTagModifier opts . getConName+ | otherwise = Tagged . nonAllNullarySumToEncoding opts+ {-# INLINE sumToEncoding #-}+ instance ( TwoElemArray f , TaggedObject f , ObjectWithSingleField f ) => SumToJSON f False where sumToJSON opts = Tagged . nonAllNullarySumToJSON opts {-# INLINE sumToJSON #-}+ sumToEncoding opts = Tagged . nonAllNullarySumToEncoding opts+ {-# INLINE sumToEncoding #-} nonAllNullarySumToJSON :: ( TwoElemArray f , TaggedObject f@@ -109,47 +141,86 @@ ) => Options -> f a -> Value nonAllNullarySumToJSON opts = case sumEncoding opts of- TaggedObject{..} -> object . taggedObject opts tagFieldName- contentsFieldName- ObjectWithSingleField -> Object . objectWithSingleField opts- TwoElemArray -> Array . twoElemArray opts+ TaggedObject{..} ->+ object . taggedObjectPairs opts tagFieldName contentsFieldName+ ObjectWithSingleField -> Object . objectWithSingleFieldObj opts+ TwoElemArray -> Array . twoElemArrayObj opts {-# INLINE nonAllNullarySumToJSON #-} +nonAllNullarySumToEncoding :: ( TwoElemArray f+ , TaggedObject f+ , ObjectWithSingleField f+ ) => Options -> f a -> B.Builder+nonAllNullarySumToEncoding opts =+ case sumEncoding opts of+ TaggedObject{..} ->+ taggedObjectEnc opts tagFieldName contentsFieldName+ ObjectWithSingleField -> objectWithSingleFieldEnc opts+ TwoElemArray -> twoElemArrayEnc opts+{-# INLINE nonAllNullarySumToEncoding #-}+ -------------------------------------------------------------------------------- class TaggedObject f where- taggedObject :: Options -> String -> String -> f a -> [Pair]+ taggedObjectPairs :: Options -> String -> String -> f a -> [Pair]+ taggedObjectEnc :: Options -> String -> String -> f a -> B.Builder instance ( TaggedObject a , TaggedObject b ) => TaggedObject (a :+: b) where- taggedObject opts tagFieldName contentsFieldName (L1 x) =- taggedObject opts tagFieldName contentsFieldName x- taggedObject opts tagFieldName contentsFieldName (R1 x) =- taggedObject opts tagFieldName contentsFieldName x- {-# INLINE taggedObject #-}+ taggedObjectPairs opts tagFieldName contentsFieldName (L1 x) =+ taggedObjectPairs opts tagFieldName contentsFieldName x+ taggedObjectPairs opts tagFieldName contentsFieldName (R1 x) =+ taggedObjectPairs opts tagFieldName contentsFieldName x+ {-# INLINE taggedObjectPairs #-} + taggedObjectEnc opts tagFieldName contentsFieldName (L1 x) =+ taggedObjectEnc opts tagFieldName contentsFieldName x+ taggedObjectEnc opts tagFieldName contentsFieldName (R1 x) =+ taggedObjectEnc opts tagFieldName contentsFieldName x+ {-# INLINE taggedObjectEnc #-}+ instance ( IsRecord a isRecord , TaggedObject' a isRecord , Constructor c ) => TaggedObject (C1 c a) where- taggedObject opts tagFieldName contentsFieldName =+ taggedObjectPairs opts tagFieldName contentsFieldName = (pack tagFieldName .= constructorTagModifier opts (conName (undefined :: t c a p)) :) . (unTagged :: Tagged isRecord [Pair] -> [Pair]) .- taggedObject' opts contentsFieldName . unM1- {-# INLINE taggedObject #-}+ taggedObjectPairs' opts contentsFieldName . unM1+ {-# INLINE taggedObjectPairs #-} + taggedObjectEnc opts tagFieldName contentsFieldName v =+ B.char7 '{' <>+ (builder tagFieldName <>+ B.char7 ':' <>+ builder (constructorTagModifier opts (conName (undefined :: t c a p)))) <>+ B.char7 ',' <>+ ((unTagged :: Tagged isRecord B.Builder -> B.Builder) .+ taggedObjectEnc' opts contentsFieldName . unM1 $ v) <>+ B.char7 '}'+ {-# INLINE taggedObjectEnc #-}+ class TaggedObject' f isRecord where- taggedObject' :: Options -> String -> f a -> Tagged isRecord [Pair]+ taggedObjectPairs' :: Options -> String -> f a -> Tagged isRecord [Pair]+ taggedObjectEnc' :: Options -> String -> f a -> Tagged isRecord B.Builder -instance (RecordToPairs f) => TaggedObject' f True where- taggedObject' opts _ = Tagged . toList . recordToPairs opts- {-# INLINE taggedObject' #-}+instance (RecordTo f) => TaggedObject' f True where+ taggedObjectPairs' opts _ = Tagged . toList . recordToPairs opts+ {-# INLINE taggedObjectPairs' #-} + taggedObjectEnc' opts _ = Tagged . recordToEncoding opts+ {-# INLINE taggedObjectEnc' #-}+ instance (GToJSON f) => TaggedObject' f False where- taggedObject' opts contentsFieldName =+ taggedObjectPairs' opts contentsFieldName = Tagged . (:[]) . (pack contentsFieldName .=) . gToJSON opts- {-# INLINE taggedObject' #-}+ {-# INLINE taggedObjectPairs' #-} + taggedObjectEnc' opts contentsFieldName =+ Tagged . (\z -> builder contentsFieldName <> B.char7 ':' <> z) .+ gbuilder opts+ {-# INLINE taggedObjectEnc' #-}+ -------------------------------------------------------------------------------- -- | Get the name of the constructor of a sum datatype.@@ -168,71 +239,124 @@ -------------------------------------------------------------------------------- class TwoElemArray f where- twoElemArray :: Options -> f a -> V.Vector Value+ twoElemArrayObj :: Options -> f a -> V.Vector Value+ twoElemArrayEnc :: Options -> f a -> B.Builder instance (TwoElemArray a, TwoElemArray b) => TwoElemArray (a :+: b) where- twoElemArray opts (L1 x) = twoElemArray opts x- twoElemArray opts (R1 x) = twoElemArray opts x- {-# INLINE twoElemArray #-}+ twoElemArrayObj opts (L1 x) = twoElemArrayObj opts x+ twoElemArrayObj opts (R1 x) = twoElemArrayObj opts x+ {-# INLINE twoElemArrayObj #-} + twoElemArrayEnc opts (L1 x) = twoElemArrayEnc opts x+ twoElemArrayEnc opts (R1 x) = twoElemArrayEnc opts x+ {-# INLINE twoElemArrayEnc #-}+ instance ( GToJSON a, ConsToJSON a , Constructor c ) => TwoElemArray (C1 c a) where- twoElemArray opts x = V.create $ do+ twoElemArrayObj opts x = V.create $ do mv <- VM.unsafeNew 2 VM.unsafeWrite mv 0 $ String $ pack $ constructorTagModifier opts $ conName (undefined :: t c a p) VM.unsafeWrite mv 1 $ gToJSON opts x return mv- {-# INLINE twoElemArray #-}+ {-# INLINE twoElemArrayObj #-} + twoElemArrayEnc opts x = fromEncoding . tuple $+ builder (constructorTagModifier opts (conName (undefined :: t c a p))) >*<+ gbuilder opts x+ {-# INLINE twoElemArrayEnc #-}+ -------------------------------------------------------------------------------- class ConsToJSON f where- consToJSON :: Options -> f a -> Value+ consToJSON :: Options -> f a -> Value+ consToEncoding :: Options -> f a -> B.Builder class ConsToJSON' f isRecord where- consToJSON' :: Options -> f a -> Tagged isRecord Value+ consToJSON' :: Options -> Bool -- ^ Are we a record with one field?+ -> f a -> Tagged isRecord Value+ consToEncoding' :: Options -> Bool -- ^ Are we a record with one field?+ -> f a -> Tagged isRecord B.Builder instance ( IsRecord f isRecord , ConsToJSON' f isRecord ) => ConsToJSON f where consToJSON opts = (unTagged :: Tagged isRecord Value -> Value)- . consToJSON' opts+ . consToJSON' opts (isUnary (undefined :: f a)) {-# INLINE consToJSON #-} -instance (RecordToPairs f) => ConsToJSON' f True where- consToJSON' opts = Tagged . object . toList . recordToPairs opts+ consToEncoding opts = (unTagged :: Tagged isRecord B.Builder -> B.Builder)+ . consToEncoding' opts (isUnary (undefined :: f a))+ {-# INLINE consToEncoding #-}++instance (RecordTo f) => ConsToJSON' f True where+ consToJSON' opts isUn f = let+ vals = toList $ recordToPairs opts f+ in case (unwrapUnaryRecords opts,isUn,vals) of+ (True,True,[(_,val)]) -> Tagged val+ _ -> Tagged $ object vals {-# INLINE consToJSON' #-} + consToEncoding' opts isUn x+ | (True,True) <- (unwrapUnaryRecords opts,isUn) = Tagged $ recordToEncoding opts x+ | otherwise = Tagged $+ B.char7 '{' <>+ recordToEncoding opts x <>+ B.char7 '}'+ {-# INLINE consToEncoding' #-}+ instance GToJSON f => ConsToJSON' f False where- consToJSON' opts = Tagged . gToJSON opts+ consToJSON' opts _ = Tagged . gToJSON opts {-# INLINE consToJSON' #-}+ consToEncoding' opts _ = Tagged . gbuilder opts+ {-# INLINE consToEncoding' #-} -------------------------------------------------------------------------------- -class RecordToPairs f where- recordToPairs :: Options -> f a -> DList Pair+class RecordTo f where+ recordToPairs :: Options -> f a -> DList Pair+ recordToEncoding :: Options -> f a -> B.Builder -instance (RecordToPairs a, RecordToPairs b) => RecordToPairs (a :*: b) where- recordToPairs opts (a :*: b) = recordToPairs opts a `mappend`+instance (RecordTo a, RecordTo b) => RecordTo (a :*: b) where+ recordToPairs opts (a :*: b) = recordToPairs opts a <> recordToPairs opts b {-# INLINE recordToPairs #-} -instance (Selector s, GToJSON a) => RecordToPairs (S1 s a) where+ recordToEncoding opts (a :*: b) = recordToEncoding opts a <>+ B.char7 ',' <>+ recordToEncoding opts b+ {-# INLINE recordToEncoding #-}++instance (Selector s, GToJSON a) => RecordTo (S1 s a) where recordToPairs = fieldToPair {-# INLINE recordToPairs #-} -instance (Selector s, ToJSON a) => RecordToPairs (S1 s (K1 i (Maybe a))) where+ recordToEncoding = fieldToEncoding+ {-# INLINE recordToEncoding #-}++instance (Selector s, ToJSON a) => RecordTo (S1 s (K1 i (Maybe a))) where recordToPairs opts (M1 k1) | omitNothingFields opts , K1 Nothing <- k1 = empty recordToPairs opts m1 = fieldToPair opts m1 {-# INLINE recordToPairs #-} + recordToEncoding opts (M1 k1) | omitNothingFields opts+ , K1 Nothing <- k1 = mempty+ recordToEncoding opts m1 = fieldToEncoding opts m1+ {-# INLINE recordToEncoding #-}+ fieldToPair :: (Selector s, GToJSON a) => Options -> S1 s a p -> DList Pair fieldToPair opts m1 = pure ( pack $ fieldLabelModifier opts $ selName m1 , gToJSON opts (unM1 m1) ) {-# INLINE fieldToPair #-} +fieldToEncoding :: (Selector s, GToJSON a) => Options -> S1 s a p -> B.Builder+fieldToEncoding opts m1 =+ builder (fieldLabelModifier opts $ selName m1) <>+ B.char7 ':' <>+ gbuilder opts (unM1 m1)+{-# INLINE fieldToEncoding #-}+ -------------------------------------------------------------------------------- class WriteProduct f where@@ -242,6 +366,7 @@ -> Int -- ^ length -> f a -> ST s ()+ encodeProduct :: Options -> f a -> B.Builder instance ( WriteProduct a , WriteProduct b ) => WriteProduct (a :*: b) where@@ -249,38 +374,59 @@ writeProduct opts mv ix lenL a writeProduct opts mv ixR lenR b where-#if MIN_VERSION_base(4,5,0) lenL = len `unsafeShiftR` 1-#else- lenL = len `shiftR` 1-#endif lenR = len - lenL ixR = ix + lenL {-# INLINE writeProduct #-} + encodeProduct opts (a :*: b) = encodeProduct opts a <>+ B.char7 ',' <>+ encodeProduct opts b+ {-# INLINE encodeProduct #-}+ instance (GToJSON a) => WriteProduct a where writeProduct opts mv ix _ = VM.unsafeWrite mv ix . gToJSON opts {-# INLINE writeProduct #-} + encodeProduct opts = gbuilder opts+ {-# INLINE encodeProduct #-}+ -------------------------------------------------------------------------------- class ObjectWithSingleField f where- objectWithSingleField :: Options -> f a -> Object+ objectWithSingleFieldObj :: Options -> f a -> Object+ objectWithSingleFieldEnc :: Options -> f a -> B.Builder instance ( ObjectWithSingleField a , ObjectWithSingleField b ) => ObjectWithSingleField (a :+: b) where- objectWithSingleField opts (L1 x) = objectWithSingleField opts x- objectWithSingleField opts (R1 x) = objectWithSingleField opts x- {-# INLINE objectWithSingleField #-}+ objectWithSingleFieldObj opts (L1 x) = objectWithSingleFieldObj opts x+ objectWithSingleFieldObj opts (R1 x) = objectWithSingleFieldObj opts x+ {-# INLINE objectWithSingleFieldObj #-} + objectWithSingleFieldEnc opts (L1 x) = objectWithSingleFieldEnc opts x+ objectWithSingleFieldEnc opts (R1 x) = objectWithSingleFieldEnc opts x+ {-# INLINE objectWithSingleFieldEnc #-}+ instance ( GToJSON a, ConsToJSON a , Constructor c ) => ObjectWithSingleField (C1 c a) where- objectWithSingleField opts = H.singleton typ . gToJSON opts+ objectWithSingleFieldObj opts = H.singleton typ . gToJSON opts where typ = pack $ constructorTagModifier opts $ conName (undefined :: t c a p)- {-# INLINE objectWithSingleField #-}+ {-# INLINE objectWithSingleFieldObj #-} + objectWithSingleFieldEnc opts v =+ B.char7 '{' <>+ builder (constructorTagModifier opts+ (conName (undefined :: t c a p))) <>+ B.char7 ':' <>+ gbuilder opts v <>+ B.char7 '}'+ {-# INLINE objectWithSingleFieldEnc #-}++gbuilder :: GToJSON f => Options -> f a -> Builder+gbuilder opts = fromEncoding . gToEncoding opts+ -------------------------------------------------------------------------------- -- Generic parseJSON @@ -448,7 +594,7 @@ {-# INLINE parseFromTaggedObject' #-} instance (FromRecord f) => FromTaggedObject'' f True where- parseFromTaggedObject'' opts _ = Tagged . parseRecord opts+ parseFromTaggedObject'' opts _ = Tagged . parseRecord opts Nothing {-# INLINE parseFromTaggedObject'' #-} instance (GFromJSON f) => FromTaggedObject'' f False where@@ -462,42 +608,56 @@ consParseJSON :: Options -> Value -> Parser (f a) class ConsFromJSON' f isRecord where- consParseJSON' :: Options -> Value -> Tagged isRecord (Parser (f a))+ consParseJSON' :: Options -> (Maybe Text) -- ^ A dummy label+ -- (Nothing to use proper label)+ -> Value -> Tagged isRecord (Parser (f a)) instance ( IsRecord f isRecord , ConsFromJSON' f isRecord ) => ConsFromJSON f where- consParseJSON opts = (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a))- . consParseJSON' opts+ consParseJSON opts v = let+ (v2,lab) = case (unwrapUnaryRecords opts,isUnary (undefined :: f a)) of+ -- use a dummy object with a dummy label+ (True,True) -> ((object [(pack "dummy",v)]),Just $ pack "dummy")+ _ ->(v,Nothing)+ in (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a))+ $ consParseJSON' opts lab v2 {-# INLINE consParseJSON #-} + instance (FromRecord f) => ConsFromJSON' f True where- consParseJSON' opts = Tagged . (withObject "record (:*:)" $ parseRecord opts)+ consParseJSON' opts mlab = Tagged . (withObject "record (:*:)"+ $ parseRecord opts mlab) {-# INLINE consParseJSON' #-} instance (GFromJSON f) => ConsFromJSON' f False where- consParseJSON' opts = Tagged . gParseJSON opts+ consParseJSON' opts _ = Tagged . gParseJSON opts {-# INLINE consParseJSON' #-} -------------------------------------------------------------------------------- class FromRecord f where- parseRecord :: Options -> Object -> Parser (f a)+ parseRecord :: Options -> (Maybe Text) -- ^ A dummy label+ -- (Nothing to use proper label)+ -> Object -> Parser (f a) instance (FromRecord a, FromRecord b) => FromRecord (a :*: b) where- parseRecord opts obj = (:*:) <$> parseRecord opts obj- <*> parseRecord opts obj+ parseRecord opts _ obj = (:*:) <$> parseRecord opts Nothing obj+ <*> parseRecord opts Nothing obj {-# INLINE parseRecord #-} instance (Selector s, GFromJSON a) => FromRecord (S1 s a) where- parseRecord opts = maybe (notFound label) (gParseJSON opts)- . H.lookup (pack label)+ parseRecord opts (Just lab) = maybe (notFound $ unpack lab)+ (gParseJSON opts) . H.lookup lab+ parseRecord opts Nothing = maybe (notFound label)+ (gParseJSON opts) . H.lookup (pack label) where label = fieldLabelModifier opts $ selName (undefined :: t s a p) {-# INLINE parseRecord #-} instance (Selector s, FromJSON a) => FromRecord (S1 s (K1 i (Maybe a))) where- parseRecord opts obj = (M1 . K1) <$> obj .:? pack label+ parseRecord _ (Just lab) obj = (M1 . K1) . join <$> obj .:? lab+ parseRecord opts Nothing obj = (M1 . K1) . join <$> obj .:? pack label where label = fieldLabelModifier opts $ selName (undefined :: t s (K1 i (Maybe a)) p)@@ -527,11 +687,7 @@ (:*:) <$> parseProduct opts arr ix lenL <*> parseProduct opts arr ixR lenR where-#if MIN_VERSION_base(4,5,0) lenL = len `unsafeShiftR` 1-#else- lenL = len `shiftR` 1-#endif ixR = ix + lenL lenR = len - lenL {-# INLINE parseProduct #-}@@ -562,12 +718,17 @@ -------------------------------------------------------------------------------- class IsRecord (f :: * -> *) isRecord | f -> isRecord+ where+ isUnary :: f a -> Bool+ isUnary = const True instance (IsRecord f isRecord) => IsRecord (f :*: g) isRecord+ where isUnary = const False instance IsRecord (M1 S NoSelector f) False instance (IsRecord f isRecord) => IsRecord (M1 S c f) isRecord instance IsRecord (K1 i c) True instance IsRecord U1 False+ where isUnary = const False --------------------------------------------------------------------------------
Data/Aeson/Types/Instances.hs view
@@ -1,20 +1,16 @@-{-# LANGUAGE CPP, DeriveDataTypeable, FlexibleContexts, FlexibleInstances,- GeneralizedNewtypeDeriving, IncoherentInstances, OverlappingInstances,- OverloadedStrings, UndecidableInstances, ViewPatterns #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--#ifdef GENERICS+{-# LANGUAGE CPP, BangPatterns, DeriveDataTypeable, FlexibleContexts,+ FlexibleInstances, GeneralizedNewtypeDeriving, IncoherentInstances,+ OverlappingInstances, OverloadedStrings, UndecidableInstances,+ ViewPatterns #-} {-# LANGUAGE DefaultSignatures #-}-#endif+{-# OPTIONS_GHC -fno-warn-orphans #-} -- TODO: Drop this when we remove support for Data.Attoparsec.Number-#if MIN_VERSION_attoparsec(0,12,0) {-# OPTIONS_GHC -fno-warn-deprecations #-}-#endif -- | -- Module: Data.Aeson.Types.Instances--- Copyright: (c) 2011-2013 Bryan O'Sullivan+-- Copyright: (c) 2011-2015 Bryan O'Sullivan -- (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Bryan O'Sullivan <bos@serpentine.com>@@ -29,13 +25,14 @@ -- ** Core JSON classes FromJSON(..) , ToJSON(..)-#ifdef GENERICS+ , KeyValue(..) -- ** Generic JSON classes , GFromJSON(..) , GToJSON(..) , genericToJSON+ , genericToEncoding , genericParseJSON-#endif+ -- * Types , DotNetTime(..) @@ -49,62 +46,78 @@ -- * Functions , fromJSON+ , ifromJSON , (.:) , (.:?) , (.!=)- , (.=)+ , tuple+ , (>*<) , typeMismatch ) where -import Control.Applicative ((<$>), (<*>), (<|>), pure, empty)-import Data.Aeson.Functions+import Control.Applicative ((<$>), (<*>), pure)+import Data.Aeson.Encode.Functions (brackets, builder, encode, foldable, list)+import Data.Aeson.Functions (hashMapKey, mapHashKeyVal, mapKey, mapKeyVal) import Data.Aeson.Types.Class import Data.Aeson.Types.Internal-import Data.Scientific (Scientific)-import qualified Data.Scientific as Scientific (coefficient, base10Exponent, fromFloatDigits, toRealFloat) import Data.Attoparsec.Number (Number(..))-import Data.Fixed-import Data.Foldable (toList)+import Data.Fixed (Fixed, HasResolution)+import Data.Foldable (Foldable, toList) import Data.Functor.Identity (Identity(..)) import Data.Hashable (Hashable(..)) import Data.Int (Int8, Int16, Int32, Int64) import Data.Maybe (fromMaybe)+import Data.Monoid ((<>), mempty) import Data.Monoid (Dual(..), First(..), Last(..)) import Data.Ratio (Ratio, (%), numerator, denominator)+import Data.Scientific (Scientific) import Data.Text (Text, pack, unpack)-import Data.Time (UTCTime, ZonedTime(..), TimeZone(..))+import Data.Time (Day, LocalTime, NominalDiffTime, UTCTime, ZonedTime) import Data.Time.Format (FormatTime, formatTime, parseTime)-import Data.Traversable (traverse)+import Data.Traversable as Tr (sequence, traverse) import Data.Vector (Vector) import Data.Word (Word, Word8, Word16, Word32, Word64) import Foreign.Storable (Storable)+import Prelude hiding (foldr)+import qualified Data.Aeson.Encode.Builder as E+import qualified Data.Aeson.Parser.Time as Time+import qualified Data.ByteString.Builder as B+import qualified Data.ByteString.Lazy as L import qualified Data.HashMap.Strict as H import qualified Data.HashSet as HashSet import qualified Data.IntMap as IntMap import qualified Data.IntSet as IntSet import qualified Data.Map as M-import qualified Data.Set as Set+import qualified Data.Scientific as Scientific import qualified Data.Sequence as Seq-import qualified Data.Tree as Tree+import qualified Data.Set as Set import qualified Data.Text as T+import qualified Data.Text.Encoding as T import qualified Data.Text.Lazy as LT+import qualified Data.Tree as Tree import qualified Data.Vector as V import qualified Data.Vector.Generic as VG+import qualified Data.Vector.Mutable as VM (unsafeNew, unsafeWrite) import qualified Data.Vector.Primitive as VP import qualified Data.Vector.Storable as VS import qualified Data.Vector.Unboxed as VU-import qualified Data.Vector.Mutable as VM ( unsafeNew, unsafeWrite ) #if MIN_VERSION_time(1,5,0)-import Data.Time.Format (defaultTimeLocale, dateTimeFmt)+import Data.Time.Format (defaultTimeLocale) #else-import System.Locale (defaultTimeLocale, dateTimeFmt)+import System.Locale (defaultTimeLocale) #endif +parseIndexedJSON :: FromJSON a => Int -> Value -> Parser a+parseIndexedJSON idx value = parseJSON value <?> Index idx+ instance (ToJSON a) => ToJSON (Identity a) where toJSON (Identity a) = toJSON a {-# INLINE toJSON #-} + toEncoding (Identity a) = toEncoding a+ {-# INLINE toEncoding #-}+ instance (FromJSON a) => FromJSON (Identity a) where parseJSON a = Identity <$> parseJSON a {-# INLINE parseJSON #-}@@ -114,6 +127,10 @@ toJSON Nothing = Null {-# INLINE toJSON #-} + toEncoding (Just a) = toEncoding a+ toEncoding Nothing = Encoding E.null_+ {-# INLINE toEncoding #-}+ instance (FromJSON a) => FromJSON (Maybe a) where parseJSON Null = pure Nothing parseJSON a = Just <$> parseJSON a@@ -124,6 +141,12 @@ toJSON (Right b) = object [right .= b] {-# INLINE toJSON #-} + toEncoding (Left a) = Encoding $+ B.shortByteString "{\"left\":" <> builder a <> B.char7 '}'+ toEncoding (Right a) = Encoding $+ B.shortByteString "{\"right\":" <> builder a <> B.char7 '}'+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b) => FromJSON (Either a b) where parseJSON (Object (H.toList -> [(key, value)])) | key == left = Left <$> parseJSON value@@ -142,6 +165,9 @@ toJSON = Bool {-# INLINE toJSON #-} + toEncoding = Encoding . E.bool+ {-# INLINE toEncoding #-}+ instance FromJSON Bool where parseJSON = withBool "Bool" pure {-# INLINE parseJSON #-}@@ -150,6 +176,9 @@ toJSON _ = emptyArray {-# INLINE toJSON #-} + toEncoding _ = E.emptyArray_+ {-# INLINE toEncoding #-}+ instance FromJSON () where parseJSON = withArray "()" $ \v -> if V.null v@@ -161,6 +190,9 @@ toJSON = String . T.pack {-# INLINE toJSON #-} + toEncoding = Encoding . E.string+ {-# INLINE toEncoding #-}+ instance FromJSON [Char] where parseJSON = withText "String" $ pure . T.unpack {-# INLINE parseJSON #-}@@ -169,6 +201,9 @@ toJSON = String . T.singleton {-# INLINE toJSON #-} + toEncoding = Encoding . E.string . (:[])+ {-# INLINE toEncoding #-}+ instance FromJSON Char where parseJSON = withText "Char" $ \t -> if T.compareLength t 1 == EQ@@ -180,6 +215,9 @@ toJSON = Number {-# INLINE toJSON #-} + toEncoding = Encoding . E.number+ {-# INLINE toEncoding #-}+ instance FromJSON Scientific where parseJSON = withScientific "Scientific" pure {-# INLINE parseJSON #-}@@ -188,6 +226,9 @@ toJSON = realFloatToJSON {-# INLINE toJSON #-} + toEncoding = realFloatToEncoding+ {-# INLINE toEncoding #-}+ instance FromJSON Double where parseJSON = parseRealFloat "Double" {-# INLINE parseJSON #-}@@ -197,6 +238,10 @@ toJSON (I i) = toJSON i {-# INLINE toJSON #-} + toEncoding (D d) = toEncoding d+ toEncoding (I i) = toEncoding i+ {-# INLINE toEncoding #-}+ instance FromJSON Number where parseJSON (Number s) = pure $ scientificToNumber s parseJSON Null = pure (D (0/0))@@ -207,6 +252,9 @@ toJSON = realFloatToJSON {-# INLINE toJSON #-} + toEncoding = realFloatToEncoding+ {-# INLINE toEncoding #-}+ instance FromJSON Float where parseJSON = parseRealFloat "Float" {-# INLINE parseJSON #-}@@ -217,6 +265,12 @@ ] {-# INLINE toJSON #-} + toEncoding r = Encoding $+ B.shortByteString "{\"numerator\":" <> builder (numerator r) <>+ B.shortByteString ",\"denominator\":" <> builder (denominator r) <>+ B.char7 '}'+ {-# INLINE toEncoding #-}+ instance FromJSON (Ratio Integer) where parseJSON = withObject "Rational" $ \obj -> (%) <$> obj .: "numerator"@@ -227,6 +281,9 @@ toJSON = Number . realToFrac {-# INLINE toJSON #-} + toEncoding = Encoding . E.number . realToFrac+ {-# INLINE toEncoding #-}+ -- | /WARNING:/ Only parse fixed-precision numbers from trusted input -- since an attacker could easily fill up the memory of the target -- system by specifying a scientific number with a big exponent like@@ -239,6 +296,9 @@ toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.intDec+ {-# INLINE toEncoding #-}+ instance FromJSON Int where parseJSON = parseIntegral "Int" {-# INLINE parseJSON #-}@@ -247,18 +307,24 @@ toJSON = Number . fromInteger {-# INLINE toJSON #-} + toEncoding = Encoding . B.integerDec+ {-# INLINE toEncoding #-}+ -- | /WARNING:/ Only parse Integers from trusted input since an -- attacker could easily fill up the memory of the target system by -- specifying a scientific number with a big exponent like -- @1e1000000000@. instance FromJSON Integer where- parseJSON = withScientific "Integral" $ pure . floor+ parseJSON = withScientific "Integral" $ pure . truncate {-# INLINE parseJSON #-} instance ToJSON Int8 where toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.int8Dec+ {-# INLINE toEncoding #-}+ instance FromJSON Int8 where parseJSON = parseIntegral "Int8" {-# INLINE parseJSON #-}@@ -267,6 +333,9 @@ toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.int16Dec+ {-# INLINE toEncoding #-}+ instance FromJSON Int16 where parseJSON = parseIntegral "Int16" {-# INLINE parseJSON #-}@@ -275,6 +344,9 @@ toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.int32Dec+ {-# INLINE toEncoding #-}+ instance FromJSON Int32 where parseJSON = parseIntegral "Int32" {-# INLINE parseJSON #-}@@ -283,6 +355,9 @@ toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.int64Dec+ {-# INLINE toEncoding #-}+ instance FromJSON Int64 where parseJSON = parseIntegral "Int64" {-# INLINE parseJSON #-}@@ -291,6 +366,9 @@ toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.wordDec+ {-# INLINE toEncoding #-}+ instance FromJSON Word where parseJSON = parseIntegral "Word" {-# INLINE parseJSON #-}@@ -299,6 +377,9 @@ toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.word8Dec+ {-# INLINE toEncoding #-}+ instance FromJSON Word8 where parseJSON = parseIntegral "Word8" {-# INLINE parseJSON #-}@@ -307,6 +388,9 @@ toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.word16Dec+ {-# INLINE toEncoding #-}+ instance FromJSON Word16 where parseJSON = parseIntegral "Word16" {-# INLINE parseJSON #-}@@ -315,6 +399,9 @@ toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.word32Dec+ {-# INLINE toEncoding #-}+ instance FromJSON Word32 where parseJSON = parseIntegral "Word32" {-# INLINE parseJSON #-}@@ -323,6 +410,9 @@ toJSON = Number . fromIntegral {-# INLINE toJSON #-} + toEncoding = Encoding . B.word64Dec+ {-# INLINE toEncoding #-}+ instance FromJSON Word64 where parseJSON = parseIntegral "Word64" {-# INLINE parseJSON #-}@@ -331,6 +421,9 @@ toJSON = String {-# INLINE toJSON #-} + toEncoding = Encoding . E.text+ {-# INLINE toEncoding #-}+ instance FromJSON Text where parseJSON = withText "Text" pure {-# INLINE parseJSON #-}@@ -339,6 +432,11 @@ toJSON = String . LT.toStrict {-# INLINE toJSON #-} + toEncoding t = Encoding $+ B.char7 '"' <>+ LT.foldrChunks (\x xs -> E.unquoted x <> xs) (B.char7 '"') t+ {-# INLINE toEncoding #-}+ instance FromJSON LT.Text where parseJSON = withText "Lazy Text" $ pure . LT.fromStrict {-# INLINE parseJSON #-}@@ -347,14 +445,21 @@ toJSON = Array . V.fromList . map toJSON {-# INLINE toJSON #-} + toEncoding xs = list xs+ {-# INLINE toEncoding #-}+ instance (FromJSON a) => FromJSON [a] where- parseJSON = withArray "[a]" $ mapM parseJSON . V.toList+ parseJSON = withArray "[a]" $ Tr.sequence .+ zipWith parseIndexedJSON [0..] . V.toList {-# INLINE parseJSON #-} -instance (ToJSON a) => ToJSON (Seq.Seq a) where+instance (Foldable t, ToJSON a) => ToJSON (t a) where toJSON = toJSON . toList {-# INLINE toJSON #-} + toEncoding = foldable+ {-# INLINE toEncoding #-}+ instance (FromJSON a) => FromJSON (Seq.Seq a) where parseJSON = withArray "Seq a" $ traverse parseJSON . Seq.fromList . V.toList {-# INLINE parseJSON #-}@@ -363,8 +468,21 @@ toJSON = Array . V.map toJSON {-# INLINE toJSON #-} + toEncoding = encodeVector+ {-# INLINE toEncoding #-}++encodeVector :: (ToJSON a, VG.Vector v a) => v a -> Encoding+encodeVector xs+ | VG.null xs = E.emptyArray_+ | otherwise = Encoding $+ B.char7 '[' <> builder (VG.unsafeHead xs) <>+ VG.foldr go (B.char7 ']') (VG.unsafeTail xs)+ where go v b = B.char7 ',' <> builder v <> b+{-# INLINE encodeVector #-}+ instance (FromJSON a) => FromJSON (Vector a) where- parseJSON = withArray "Vector a" $ V.mapM parseJSON+ parseJSON = withArray "Vector a" $ V.mapM (uncurry parseIndexedJSON) .+ V.indexed {-# INLINE parseJSON #-} vectorToJSON :: (VG.Vector v a, ToJSON a) => v a -> Value@@ -372,31 +490,48 @@ {-# INLINE vectorToJSON #-} vectorParseJSON :: (FromJSON a, VG.Vector w a) => String -> Value -> Parser (w a)-vectorParseJSON s = withArray s $ fmap V.convert . V.mapM parseJSON+vectorParseJSON s = withArray s $ fmap V.convert . V.mapM (uncurry parseIndexedJSON) . V.indexed {-# INLINE vectorParseJSON #-} instance (Storable a, ToJSON a) => ToJSON (VS.Vector a) where toJSON = vectorToJSON+ {-# INLINE toJSON #-} + toEncoding = encodeVector+ {-# INLINE toEncoding #-}+ instance (Storable a, FromJSON a) => FromJSON (VS.Vector a) where parseJSON = vectorParseJSON "Data.Vector.Storable.Vector a" instance (VP.Prim a, ToJSON a) => ToJSON (VP.Vector a) where toJSON = vectorToJSON+ {-# INLINE toJSON #-} + toEncoding = encodeVector+ {-# INLINE toEncoding #-}+ instance (VP.Prim a, FromJSON a) => FromJSON (VP.Vector a) where parseJSON = vectorParseJSON "Data.Vector.Primitive.Vector a"+ {-# INLINE parseJSON #-} instance (VG.Vector VU.Vector a, ToJSON a) => ToJSON (VU.Vector a) where toJSON = vectorToJSON+ {-# INLINE toJSON #-} + toEncoding = encodeVector+ {-# INLINE toEncoding #-}+ instance (VG.Vector VU.Vector a, FromJSON a) => FromJSON (VU.Vector a) where parseJSON = vectorParseJSON "Data.Vector.Unboxed.Vector a"+ {-# INLINE parseJSON #-} instance (ToJSON a) => ToJSON (Set.Set a) where toJSON = toJSON . Set.toList {-# INLINE toJSON #-} + toEncoding = encodeSet Set.minView Set.foldr+ {-# INLINE toEncoding #-}+ instance (Ord a, FromJSON a) => FromJSON (Set.Set a) where parseJSON = fmap Set.fromList . parseJSON {-# INLINE parseJSON #-}@@ -405,6 +540,9 @@ toJSON = toJSON . HashSet.toList {-# INLINE toJSON #-} + toEncoding = foldable+ {-# INLINE toEncoding #-}+ instance (Eq a, Hashable a, FromJSON a) => FromJSON (HashSet.HashSet a) where parseJSON = fmap HashSet.fromList . parseJSON {-# INLINE parseJSON #-}@@ -413,6 +551,21 @@ toJSON = toJSON . IntSet.toList {-# INLINE toJSON #-} + toEncoding = encodeSet IntSet.minView IntSet.foldr+ {-# INLINE toEncoding #-}++encodeSet :: (ToJSON a) =>+ (s -> Maybe (a, s))+ -> ((a -> B.Builder -> B.Builder) -> B.Builder -> s -> B.Builder)+ -> s -> Encoding+encodeSet minView foldr xs =+ case minView xs of+ Nothing -> E.emptyArray_+ Just (m,ys) -> Encoding $+ B.char7 '[' <> builder m <> foldr go (B.char7 ']') ys+ where go v b = B.char7 ',' <> builder v <> b+{-# INLINE encodeSet #-}+ instance FromJSON IntSet.IntSet where parseJSON = fmap IntSet.fromList . parseJSON {-# INLINE parseJSON #-}@@ -421,6 +574,9 @@ toJSON = toJSON . IntMap.toList {-# INLINE toJSON #-} + toEncoding = toEncoding . IntMap.toList+ {-# INLINE toEncoding #-}+ instance FromJSON a => FromJSON (IntMap.IntMap a) where parseJSON = fmap IntMap.fromList . parseJSON {-# INLINE parseJSON #-}@@ -429,61 +585,123 @@ toJSON = Object . M.foldrWithKey (\k -> H.insert k . toJSON) H.empty {-# INLINE toJSON #-} + toEncoding = encodeMap M.minViewWithKey M.foldrWithKey+ {-# INLINE toEncoding #-}++encodeMap :: (ToJSON k, ToJSON v) =>+ (m -> Maybe ((k,v), m))+ -> ((k -> v -> B.Builder -> B.Builder) -> B.Builder -> m -> B.Builder)+ -> m -> Encoding+encodeMap minViewWithKey foldrWithKey xs =+ case minViewWithKey xs of+ Nothing -> E.emptyObject_+ Just ((k,v),ys) -> Encoding $+ B.char7 '{' <> encodeKV k v <>+ foldrWithKey go (B.char7 '}') ys+ where go k v b = B.char7 ',' <> encodeKV k v <> b+{-# INLINE encodeMap #-}++encodeWithKey :: (ToJSON k, ToJSON v) =>+ ((k -> v -> Series -> Series) -> Series -> m -> Series)+ -> m -> Encoding+encodeWithKey foldrWithKey = brackets '{' '}' . foldrWithKey go mempty+ where go k v c = Value (Encoding $ encodeKV k v) <> c+{-# INLINE encodeWithKey #-}++encodeKV :: (ToJSON k, ToJSON v) => k -> v -> B.Builder+encodeKV k v = builder k <> B.char7 ':' <> builder v+{-# INLINE encodeKV #-}+ instance (FromJSON v) => FromJSON (M.Map Text v) where parseJSON = withObject "Map Text a" $- fmap (H.foldrWithKey M.insert M.empty) . traverse parseJSON+ fmap (H.foldrWithKey M.insert M.empty) . H.traverseWithKey (\k v -> parseJSON v <?> Key k) instance (ToJSON v) => ToJSON (M.Map LT.Text v) where toJSON = Object . mapHashKeyVal LT.toStrict toJSON+ {-# INLINE toJSON #-} + toEncoding = encodeMap M.minViewWithKey M.foldrWithKey+ {-# INLINE toEncoding #-}+ instance (FromJSON v) => FromJSON (M.Map LT.Text v) where parseJSON = fmap (hashMapKey LT.fromStrict) . parseJSON+ {-# INLINE parseJSON #-} instance (ToJSON v) => ToJSON (M.Map String v) where toJSON = Object . mapHashKeyVal pack toJSON+ {-# INLINE toJSON #-} + toEncoding = encodeMap M.minViewWithKey M.foldrWithKey+ {-# INLINE toEncoding #-}+ instance (FromJSON v) => FromJSON (M.Map String v) where parseJSON = fmap (hashMapKey unpack) . parseJSON+ {-# INLINE parseJSON #-} instance (ToJSON v) => ToJSON (H.HashMap Text v) where toJSON = Object . H.map toJSON {-# INLINE toJSON #-} + toEncoding = encodeWithKey H.foldrWithKey+ {-# INLINE toEncoding #-}+ instance (FromJSON v) => FromJSON (H.HashMap Text v) where- parseJSON = withObject "HashMap Text a" $ traverse parseJSON+ parseJSON = withObject "HashMap Text a" $ H.traverseWithKey (\k v -> parseJSON v <?> Key k)+ {-# INLINE parseJSON #-} instance (ToJSON v) => ToJSON (H.HashMap LT.Text v) where toJSON = Object . mapKeyVal LT.toStrict toJSON+ {-# INLINE toJSON #-} + toEncoding = encodeWithKey H.foldrWithKey+ {-# INLINE toEncoding #-}+ instance (FromJSON v) => FromJSON (H.HashMap LT.Text v) where parseJSON = fmap (mapKey LT.fromStrict) . parseJSON+ {-# INLINE parseJSON #-} instance (ToJSON v) => ToJSON (H.HashMap String v) where toJSON = Object . mapKeyVal pack toJSON+ {-# INLINE toJSON #-} + toEncoding = encodeWithKey H.foldrWithKey+ {-# INLINE toEncoding #-}+ instance (FromJSON v) => FromJSON (H.HashMap String v) where parseJSON = fmap (mapKey unpack) . parseJSON+ {-# INLINE parseJSON #-} instance (ToJSON v) => ToJSON (Tree.Tree v) where toJSON (Tree.Node root branches) = toJSON (root,branches)+ {-# INLINE toJSON #-} + toEncoding (Tree.Node root branches) = toEncoding (root,branches)+ {-# INLINE toEncoding #-}+ instance (FromJSON v) => FromJSON (Tree.Tree v) where parseJSON j = uncurry Tree.Node <$> parseJSON j+ {-# INLINE parseJSON #-} instance ToJSON Value where toJSON a = a {-# INLINE toJSON #-} + toEncoding = Encoding . E.encodeToBuilder+ {-# INLINE toEncoding #-}+ instance FromJSON Value where parseJSON a = pure a {-# INLINE parseJSON #-} instance ToJSON DotNetTime where- toJSON (DotNetTime t) =- String (pack (secs ++ formatMillis t ++ ")/"))- where secs = formatTime defaultTimeLocale "/Date(%s" t- {-# INLINE toJSON #-}+ toJSON = toJSON . dotNetTime + toEncoding = toEncoding . dotNetTime++dotNetTime :: DotNetTime -> String+dotNetTime (DotNetTime t) = secs ++ formatMillis t ++ ")/"+ where secs = formatTime defaultTimeLocale "/Date(%s" t+ instance FromJSON DotNetTime where parseJSON = withText "DotNetTime" $ \t -> let (s,m) = T.splitAt (T.length t - 5) t@@ -493,66 +711,71 @@ _ -> fail "could not parse .NET time" {-# INLINE parseJSON #-} +instance ToJSON Day where+ toJSON = stringEncoding+ toEncoding z = Encoding (E.day z)++instance FromJSON Day where+ parseJSON = withText "Day" (Time.run Time.day)++instance ToJSON LocalTime where+ toJSON = stringEncoding+ toEncoding z = Encoding (E.localTime z)++instance FromJSON LocalTime where+ parseJSON = withText "LocalTime" (Time.run Time.localTime)+ instance ToJSON ZonedTime where- toJSON t = String $ pack $ formatTime defaultTimeLocale format t- where- format = "%FT%T." ++ formatMillis t ++ tzFormat- tzFormat- | 0 == timeZoneMinutes (zonedTimeZone t) = "Z"- | otherwise = "%z"+ toJSON = stringEncoding -formatMillis :: (FormatTime t) => t -> String-formatMillis = take 3 . formatSubseconds+ toEncoding z = Encoding (E.zonedTime z) -formatSubseconds :: (FormatTime t) => t -> String-formatSubseconds = formatTime defaultTimeLocale "%q"+formatMillis :: (FormatTime t) => t -> String+formatMillis = take 3 . formatTime defaultTimeLocale "%q" instance FromJSON ZonedTime where- parseJSON (String t) =- tryFormats alternateFormats- <|> fail "could not parse ECMA-262 ISO-8601 date"- where- tryFormat f =- case parseTime defaultTimeLocale f (unpack t) of- Just d -> pure d- Nothing -> empty- tryFormats = foldr1 (<|>) . map tryFormat- alternateFormats =- "%FT%T%QZ" : -- (javascript new Date().toISOString())- "%F %T%Q%z" : -- (postgres)- "%F %T%Q %Z" : -- (time's Show format)- "%FT%T%Q%z" :- "%Y-%mT%T%Q" :- "%Y-%mT%R" :- "%Y-%mT%T" :- "%Y-%mT%T%QZ" :- "%Y-%mT%T%Q%z" :- "%YT%T%Q" :- "%YT%R" :- "%YT%T" :- "%YT%T%QZ" :- "%YT%T%Q%z" :- "%FT%T%Q" :- "%FT%R" :- "%FT%T" :- dateTimeFmt defaultTimeLocale :- []-- parseJSON v = typeMismatch "ZonedTime" v+ parseJSON = withText "ZonedTime" (Time.run Time.zonedTime) instance ToJSON UTCTime where- toJSON t = String $ pack $ formatTime defaultTimeLocale format t- where- format = "%FT%T." ++ formatSubseconds t ++ "Z"- {-# INLINE toJSON #-}+ toJSON = stringEncoding + toEncoding t = Encoding (E.utcTime t)++-- | Encode something to a JSON string.+stringEncoding :: (ToJSON a) => a -> Value+stringEncoding = String . T.decodeLatin1 . L.toStrict . encode+{-# INLINE stringEncoding #-}+ instance FromJSON UTCTime where- parseJSON = withText "UTCTime" $ \t ->- case parseTime defaultTimeLocale "%FT%T%QZ" (unpack t) of- Just d -> pure d- _ -> fail "could not parse ISO-8601 date"+ parseJSON = withText "UTCTime" (Time.run Time.utcTime)++instance ToJSON NominalDiffTime where+ toJSON = Number . realToFrac+ {-# INLINE toJSON #-}++ toEncoding = Encoding . E.number . realToFrac+ {-# INLINE toEncoding #-}++-- | /WARNING:/ Only parse lengths of time from trusted input+-- since an attacker could easily fill up the memory of the target+-- system by specifying a scientific number with a big exponent like+-- @1e1000000000@.+instance FromJSON NominalDiffTime where+ parseJSON = withScientific "NominalDiffTime" $ pure . realToFrac {-# INLINE parseJSON #-} +parseJSONElemAtIndex :: FromJSON a => Int -> Vector Value -> Parser a+parseJSONElemAtIndex idx ary = parseJSON (V.unsafeIndex ary idx) <?> Index idx++tuple :: B.Builder -> Encoding+tuple b = Encoding (B.char7 '[' <> b <> B.char7 ']')+{-# INLINE tuple #-}++(>*<) :: B.Builder -> B.Builder -> B.Builder+a >*< b = a <> B.char7 ',' <> b+{-# INLINE (>*<) #-}+infixr 6 >*<+ instance (ToJSON a, ToJSON b) => ToJSON (a,b) where toJSON (a,b) = Array $ V.create $ do mv <- VM.unsafeNew 2@@ -561,12 +784,16 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b) = tuple $+ builder a >*< builder b+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b) => FromJSON (a,b) where parseJSON = withArray "(a,b)" $ \ab -> let n = V.length ab in if n == 2- then (,) <$> parseJSON (V.unsafeIndex ab 0)- <*> parseJSON (V.unsafeIndex ab 1)+ then (,) <$> parseJSONElemAtIndex 0 ab+ <*> parseJSONElemAtIndex 1 ab else fail $ "cannot unpack array of length " ++ show n ++ " into a pair" {-# INLINE parseJSON #-}@@ -580,13 +807,19 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c) = tuple $+ builder a >*<+ builder b >*<+ builder c+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c) => FromJSON (a,b,c) where parseJSON = withArray "(a,b,c)" $ \abc -> let n = V.length abc in if n == 3- then (,,) <$> parseJSON (V.unsafeIndex abc 0)- <*> parseJSON (V.unsafeIndex abc 1)- <*> parseJSON (V.unsafeIndex abc 2)+ then (,,) <$> parseJSONElemAtIndex 0 abc+ <*> parseJSONElemAtIndex 1 abc+ <*> parseJSONElemAtIndex 2 abc else fail $ "cannot unpack array of length " ++ show n ++ " into a 3-tuple" {-# INLINE parseJSON #-}@@ -601,15 +834,22 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d) => FromJSON (a,b,c,d) where parseJSON = withArray "(a,b,c,d)" $ \abcd -> let n = V.length abcd in if n == 4- then (,,,) <$> parseJSON (V.unsafeIndex abcd 0)- <*> parseJSON (V.unsafeIndex abcd 1)- <*> parseJSON (V.unsafeIndex abcd 2)- <*> parseJSON (V.unsafeIndex abcd 3)+ then (,,,) <$> parseJSONElemAtIndex 0 abcd+ <*> parseJSONElemAtIndex 1 abcd+ <*> parseJSONElemAtIndex 2 abcd+ <*> parseJSONElemAtIndex 3 abcd else fail $ "cannot unpack array of length " ++ show n ++ " into a 4-tuple" {-# INLINE parseJSON #-}@@ -626,16 +866,24 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e) => FromJSON (a,b,c,d,e) where parseJSON = withArray "(a,b,c,d,e)" $ \abcde -> let n = V.length abcde in if n == 5- then (,,,,) <$> parseJSON (V.unsafeIndex abcde 0)- <*> parseJSON (V.unsafeIndex abcde 1)- <*> parseJSON (V.unsafeIndex abcde 2)- <*> parseJSON (V.unsafeIndex abcde 3)- <*> parseJSON (V.unsafeIndex abcde 4)+ then (,,,,) <$> parseJSONElemAtIndex 0 abcde+ <*> parseJSONElemAtIndex 1 abcde+ <*> parseJSONElemAtIndex 2 abcde+ <*> parseJSONElemAtIndex 3 abcde+ <*> parseJSONElemAtIndex 4 abcde else fail $ "cannot unpack array of length " ++ show n ++ " into a 5-tuple" {-# INLINE parseJSON #-}@@ -653,17 +901,26 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e, FromJSON f) => FromJSON (a,b,c,d,e,f) where parseJSON = withArray "(a,b,c,d,e,f)" $ \abcdef -> let n = V.length abcdef in if n == 6- then (,,,,,) <$> parseJSON (V.unsafeIndex abcdef 0)- <*> parseJSON (V.unsafeIndex abcdef 1)- <*> parseJSON (V.unsafeIndex abcdef 2)- <*> parseJSON (V.unsafeIndex abcdef 3)- <*> parseJSON (V.unsafeIndex abcdef 4)- <*> parseJSON (V.unsafeIndex abcdef 5)+ then (,,,,,) <$> parseJSONElemAtIndex 0 abcdef+ <*> parseJSONElemAtIndex 1 abcdef+ <*> parseJSONElemAtIndex 2 abcdef+ <*> parseJSONElemAtIndex 3 abcdef+ <*> parseJSONElemAtIndex 4 abcdef+ <*> parseJSONElemAtIndex 5 abcdef else fail $ "cannot unpack array of length " ++ show n ++ " into a 6-tuple" {-# INLINE parseJSON #-}@@ -682,18 +939,28 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f,g) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f >*<+ builder g+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e, FromJSON f, FromJSON g) => FromJSON (a,b,c,d,e,f,g) where parseJSON = withArray "(a,b,c,d,e,f,g)" $ \abcdefg -> let n = V.length abcdefg in if n == 7- then (,,,,,,) <$> parseJSON (V.unsafeIndex abcdefg 0)- <*> parseJSON (V.unsafeIndex abcdefg 1)- <*> parseJSON (V.unsafeIndex abcdefg 2)- <*> parseJSON (V.unsafeIndex abcdefg 3)- <*> parseJSON (V.unsafeIndex abcdefg 4)- <*> parseJSON (V.unsafeIndex abcdefg 5)- <*> parseJSON (V.unsafeIndex abcdefg 6)+ then (,,,,,,) <$> parseJSONElemAtIndex 0 abcdefg+ <*> parseJSONElemAtIndex 1 abcdefg+ <*> parseJSONElemAtIndex 2 abcdefg+ <*> parseJSONElemAtIndex 3 abcdefg+ <*> parseJSONElemAtIndex 4 abcdefg+ <*> parseJSONElemAtIndex 5 abcdefg+ <*> parseJSONElemAtIndex 6 abcdefg else fail $ "cannot unpack array of length " ++ show n ++ " into a 7-tuple" {-# INLINE parseJSON #-}@@ -713,6 +980,17 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f,g,h) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f >*<+ builder g >*<+ builder h+ {-# INLINE toEncoding #-}+ 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@@ -722,14 +1000,14 @@ then fail $ "cannot unpack array of length " ++ show n ++ " into an 8-tuple" else (,,,,,,,)- <$> parseJSON (V.unsafeIndex ary 0)- <*> parseJSON (V.unsafeIndex ary 1)- <*> parseJSON (V.unsafeIndex ary 2)- <*> parseJSON (V.unsafeIndex ary 3)- <*> parseJSON (V.unsafeIndex ary 4)- <*> parseJSON (V.unsafeIndex ary 5)- <*> parseJSON (V.unsafeIndex ary 6)- <*> parseJSON (V.unsafeIndex ary 7)+ <$> parseJSONElemAtIndex 0 ary+ <*> parseJSONElemAtIndex 1 ary+ <*> parseJSONElemAtIndex 2 ary+ <*> parseJSONElemAtIndex 3 ary+ <*> parseJSONElemAtIndex 4 ary+ <*> parseJSONElemAtIndex 5 ary+ <*> parseJSONElemAtIndex 6 ary+ <*> parseJSONElemAtIndex 7 ary {-# INLINE parseJSON #-} instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,@@ -748,6 +1026,18 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f,g,h,i) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f >*<+ builder g >*<+ builder h >*<+ builder i+ {-# INLINE toEncoding #-}+ 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@@ -757,15 +1047,15 @@ then fail $ "cannot unpack array of length " ++ show n ++ " into a 9-tuple" else (,,,,,,,,)- <$> parseJSON (V.unsafeIndex ary 0)- <*> parseJSON (V.unsafeIndex ary 1)- <*> parseJSON (V.unsafeIndex ary 2)- <*> parseJSON (V.unsafeIndex ary 3)- <*> parseJSON (V.unsafeIndex ary 4)- <*> parseJSON (V.unsafeIndex ary 5)- <*> parseJSON (V.unsafeIndex ary 6)- <*> parseJSON (V.unsafeIndex ary 7)- <*> parseJSON (V.unsafeIndex ary 8)+ <$> parseJSONElemAtIndex 0 ary+ <*> parseJSONElemAtIndex 1 ary+ <*> parseJSONElemAtIndex 2 ary+ <*> parseJSONElemAtIndex 3 ary+ <*> parseJSONElemAtIndex 4 ary+ <*> parseJSONElemAtIndex 5 ary+ <*> parseJSONElemAtIndex 6 ary+ <*> parseJSONElemAtIndex 7 ary+ <*> parseJSONElemAtIndex 8 ary {-# INLINE parseJSON #-} instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,@@ -786,6 +1076,19 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f,g,h,i,j) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f >*<+ builder g >*<+ builder h >*<+ builder i >*<+ builder j+ {-# INLINE toEncoding #-}+ 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@@ -795,16 +1098,16 @@ then fail $ "cannot unpack array of length " ++ show n ++ " into a 10-tuple" else (,,,,,,,,,)- <$> parseJSON (V.unsafeIndex ary 0)- <*> parseJSON (V.unsafeIndex ary 1)- <*> parseJSON (V.unsafeIndex ary 2)- <*> parseJSON (V.unsafeIndex ary 3)- <*> parseJSON (V.unsafeIndex ary 4)- <*> parseJSON (V.unsafeIndex ary 5)- <*> parseJSON (V.unsafeIndex ary 6)- <*> parseJSON (V.unsafeIndex ary 7)- <*> parseJSON (V.unsafeIndex ary 8)- <*> parseJSON (V.unsafeIndex ary 9)+ <$> parseJSONElemAtIndex 0 ary+ <*> parseJSONElemAtIndex 1 ary+ <*> parseJSONElemAtIndex 2 ary+ <*> parseJSONElemAtIndex 3 ary+ <*> parseJSONElemAtIndex 4 ary+ <*> parseJSONElemAtIndex 5 ary+ <*> parseJSONElemAtIndex 6 ary+ <*> parseJSONElemAtIndex 7 ary+ <*> parseJSONElemAtIndex 8 ary+ <*> parseJSONElemAtIndex 9 ary {-# INLINE parseJSON #-} instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,@@ -826,6 +1129,20 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f,g,h,i,j,k) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f >*<+ builder g >*<+ builder h >*<+ builder i >*<+ builder j >*<+ builder k+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e, FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j, FromJSON k) =>@@ -836,17 +1153,17 @@ then fail $ "cannot unpack array of length " ++ show n ++ " into an 11-tuple" else (,,,,,,,,,,)- <$> parseJSON (V.unsafeIndex ary 0)- <*> parseJSON (V.unsafeIndex ary 1)- <*> parseJSON (V.unsafeIndex ary 2)- <*> parseJSON (V.unsafeIndex ary 3)- <*> parseJSON (V.unsafeIndex ary 4)- <*> parseJSON (V.unsafeIndex ary 5)- <*> parseJSON (V.unsafeIndex ary 6)- <*> parseJSON (V.unsafeIndex ary 7)- <*> parseJSON (V.unsafeIndex ary 8)- <*> parseJSON (V.unsafeIndex ary 9)- <*> parseJSON (V.unsafeIndex ary 10)+ <$> parseJSONElemAtIndex 0 ary+ <*> parseJSONElemAtIndex 1 ary+ <*> parseJSONElemAtIndex 2 ary+ <*> parseJSONElemAtIndex 3 ary+ <*> parseJSONElemAtIndex 4 ary+ <*> parseJSONElemAtIndex 5 ary+ <*> parseJSONElemAtIndex 6 ary+ <*> parseJSONElemAtIndex 7 ary+ <*> parseJSONElemAtIndex 8 ary+ <*> parseJSONElemAtIndex 9 ary+ <*> parseJSONElemAtIndex 10 ary {-# INLINE parseJSON #-} instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,@@ -869,6 +1186,21 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f,g,h,i,j,k,l) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f >*<+ builder g >*<+ builder h >*<+ builder i >*<+ builder j >*<+ builder k >*<+ builder l+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e, FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j, FromJSON k, FromJSON l) =>@@ -879,18 +1211,18 @@ then fail $ "cannot unpack array of length " ++ show n ++ " into a 12-tuple" else (,,,,,,,,,,,)- <$> parseJSON (V.unsafeIndex ary 0)- <*> parseJSON (V.unsafeIndex ary 1)- <*> parseJSON (V.unsafeIndex ary 2)- <*> parseJSON (V.unsafeIndex ary 3)- <*> parseJSON (V.unsafeIndex ary 4)- <*> parseJSON (V.unsafeIndex ary 5)- <*> parseJSON (V.unsafeIndex ary 6)- <*> parseJSON (V.unsafeIndex ary 7)- <*> parseJSON (V.unsafeIndex ary 8)- <*> parseJSON (V.unsafeIndex ary 9)- <*> parseJSON (V.unsafeIndex ary 10)- <*> parseJSON (V.unsafeIndex ary 11)+ <$> parseJSONElemAtIndex 0 ary+ <*> parseJSONElemAtIndex 1 ary+ <*> parseJSONElemAtIndex 2 ary+ <*> parseJSONElemAtIndex 3 ary+ <*> parseJSONElemAtIndex 4 ary+ <*> parseJSONElemAtIndex 5 ary+ <*> parseJSONElemAtIndex 6 ary+ <*> parseJSONElemAtIndex 7 ary+ <*> parseJSONElemAtIndex 8 ary+ <*> parseJSONElemAtIndex 9 ary+ <*> parseJSONElemAtIndex 10 ary+ <*> parseJSONElemAtIndex 11 ary {-# INLINE parseJSON #-} instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,@@ -915,6 +1247,22 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f,g,h,i,j,k,l,m) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f >*<+ builder g >*<+ builder h >*<+ builder i >*<+ builder j >*<+ builder k >*<+ builder l >*<+ builder m+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e, FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j, FromJSON k, FromJSON l, FromJSON m) =>@@ -925,19 +1273,19 @@ then fail $ "cannot unpack array of length " ++ show n ++ " into a 13-tuple" else (,,,,,,,,,,,,)- <$> parseJSON (V.unsafeIndex ary 0)- <*> parseJSON (V.unsafeIndex ary 1)- <*> parseJSON (V.unsafeIndex ary 2)- <*> parseJSON (V.unsafeIndex ary 3)- <*> parseJSON (V.unsafeIndex ary 4)- <*> parseJSON (V.unsafeIndex ary 5)- <*> parseJSON (V.unsafeIndex ary 6)- <*> parseJSON (V.unsafeIndex ary 7)- <*> parseJSON (V.unsafeIndex ary 8)- <*> parseJSON (V.unsafeIndex ary 9)- <*> parseJSON (V.unsafeIndex ary 10)- <*> parseJSON (V.unsafeIndex ary 11)- <*> parseJSON (V.unsafeIndex ary 12)+ <$> parseJSONElemAtIndex 0 ary+ <*> parseJSONElemAtIndex 1 ary+ <*> parseJSONElemAtIndex 2 ary+ <*> parseJSONElemAtIndex 3 ary+ <*> parseJSONElemAtIndex 4 ary+ <*> parseJSONElemAtIndex 5 ary+ <*> parseJSONElemAtIndex 6 ary+ <*> parseJSONElemAtIndex 7 ary+ <*> parseJSONElemAtIndex 8 ary+ <*> parseJSONElemAtIndex 9 ary+ <*> parseJSONElemAtIndex 10 ary+ <*> parseJSONElemAtIndex 11 ary+ <*> parseJSONElemAtIndex 12 ary {-# INLINE parseJSON #-} instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,@@ -963,6 +1311,23 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f,g,h,i,j,k,l,m,n) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f >*<+ builder g >*<+ builder h >*<+ builder i >*<+ builder j >*<+ builder k >*<+ builder l >*<+ builder m >*<+ builder n+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e, FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j, FromJSON k, FromJSON l, FromJSON m, FromJSON n) =>@@ -973,20 +1338,20 @@ then fail $ "cannot unpack array of length " ++ show n ++ " into a 14-tuple" else (,,,,,,,,,,,,,)- <$> parseJSON (V.unsafeIndex ary 0)- <*> parseJSON (V.unsafeIndex ary 1)- <*> parseJSON (V.unsafeIndex ary 2)- <*> parseJSON (V.unsafeIndex ary 3)- <*> parseJSON (V.unsafeIndex ary 4)- <*> parseJSON (V.unsafeIndex ary 5)- <*> parseJSON (V.unsafeIndex ary 6)- <*> parseJSON (V.unsafeIndex ary 7)- <*> parseJSON (V.unsafeIndex ary 8)- <*> parseJSON (V.unsafeIndex ary 9)- <*> parseJSON (V.unsafeIndex ary 10)- <*> parseJSON (V.unsafeIndex ary 11)- <*> parseJSON (V.unsafeIndex ary 12)- <*> parseJSON (V.unsafeIndex ary 13)+ <$> parseJSONElemAtIndex 0 ary+ <*> parseJSONElemAtIndex 1 ary+ <*> parseJSONElemAtIndex 2 ary+ <*> parseJSONElemAtIndex 3 ary+ <*> parseJSONElemAtIndex 4 ary+ <*> parseJSONElemAtIndex 5 ary+ <*> parseJSONElemAtIndex 6 ary+ <*> parseJSONElemAtIndex 7 ary+ <*> parseJSONElemAtIndex 8 ary+ <*> parseJSONElemAtIndex 9 ary+ <*> parseJSONElemAtIndex 10 ary+ <*> parseJSONElemAtIndex 11 ary+ <*> parseJSONElemAtIndex 12 ary+ <*> parseJSONElemAtIndex 13 ary {-# INLINE parseJSON #-} instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,@@ -1013,6 +1378,24 @@ return mv {-# INLINE toJSON #-} + toEncoding (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) = tuple $+ builder a >*<+ builder b >*<+ builder c >*<+ builder d >*<+ builder e >*<+ builder f >*<+ builder g >*<+ builder h >*<+ builder i >*<+ builder j >*<+ builder k >*<+ builder l >*<+ builder m >*<+ builder n >*<+ builder o+ {-# INLINE toEncoding #-}+ instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e, FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j, FromJSON k, FromJSON l, FromJSON m, FromJSON n, FromJSON o) =>@@ -1023,27 +1406,30 @@ then fail $ "cannot unpack array of length " ++ show n ++ " into a 15-tuple" else (,,,,,,,,,,,,,,)- <$> parseJSON (V.unsafeIndex ary 0)- <*> parseJSON (V.unsafeIndex ary 1)- <*> parseJSON (V.unsafeIndex ary 2)- <*> parseJSON (V.unsafeIndex ary 3)- <*> parseJSON (V.unsafeIndex ary 4)- <*> parseJSON (V.unsafeIndex ary 5)- <*> parseJSON (V.unsafeIndex ary 6)- <*> parseJSON (V.unsafeIndex ary 7)- <*> parseJSON (V.unsafeIndex ary 8)- <*> parseJSON (V.unsafeIndex ary 9)- <*> parseJSON (V.unsafeIndex ary 10)- <*> parseJSON (V.unsafeIndex ary 11)- <*> parseJSON (V.unsafeIndex ary 12)- <*> parseJSON (V.unsafeIndex ary 13)- <*> parseJSON (V.unsafeIndex ary 14)+ <$> parseJSONElemAtIndex 0 ary+ <*> parseJSONElemAtIndex 1 ary+ <*> parseJSONElemAtIndex 2 ary+ <*> parseJSONElemAtIndex 3 ary+ <*> parseJSONElemAtIndex 4 ary+ <*> parseJSONElemAtIndex 5 ary+ <*> parseJSONElemAtIndex 6 ary+ <*> parseJSONElemAtIndex 7 ary+ <*> parseJSONElemAtIndex 8 ary+ <*> parseJSONElemAtIndex 9 ary+ <*> parseJSONElemAtIndex 10 ary+ <*> parseJSONElemAtIndex 11 ary+ <*> parseJSONElemAtIndex 12 ary+ <*> parseJSONElemAtIndex 13 ary+ <*> parseJSONElemAtIndex 14 ary {-# INLINE parseJSON #-} instance ToJSON a => ToJSON (Dual a) where toJSON = toJSON . getDual {-# INLINE toJSON #-} + toEncoding = toEncoding . getDual+ {-# INLINE toEncoding #-}+ instance FromJSON a => FromJSON (Dual a) where parseJSON = fmap Dual . parseJSON {-# INLINE parseJSON #-}@@ -1052,6 +1438,9 @@ toJSON = toJSON . getFirst {-# INLINE toJSON #-} + toEncoding = toEncoding . getFirst+ {-# INLINE toEncoding #-}+ instance FromJSON a => FromJSON (First a) where parseJSON = fmap First . parseJSON {-# INLINE parseJSON #-}@@ -1060,6 +1449,9 @@ toJSON = toJSON . getLast {-# INLINE toJSON #-} + toEncoding = toEncoding . getLast+ {-# INLINE toEncoding #-}+ instance FromJSON a => FromJSON (Last a) where parseJSON = fmap Last . parseJSON {-# INLINE parseJSON #-}@@ -1106,16 +1498,25 @@ withBool expected _ v = typeMismatch expected v {-# INLINE withBool #-} --- | Construct a 'Pair' from a key and a value.-(.=) :: ToJSON a => Text -> a -> Pair-name .= value = (name, toJSON value)-{-# INLINE (.=) #-}+instance KeyValue Pair where+ name .= value = (name, toJSON value)+ {-# INLINE (.=) #-} +instance KeyValue Series where+ name .= value = Value . Encoding $+ E.text name <> B.char7 ':' <> builder value+ {-# INLINE (.=) #-}+ -- | Convert a value from JSON, failing if the types do not match. fromJSON :: (FromJSON a) => Value -> Result a fromJSON = parse parseJSON {-# INLINE fromJSON #-} +-- | Convert a value from JSON, failing if the types do not match.+ifromJSON :: (FromJSON a) => Value -> IResult a+ifromJSON = iparse parseJSON+{-# INLINE ifromJSON #-}+ -- | Retrieve the value associated with the given key of an 'Object'. -- The result is 'empty' if the key is not present or the value cannot -- be converted to the desired type.@@ -1126,7 +1527,10 @@ (.:) :: (FromJSON a) => Object -> Text -> Parser a obj .: key = case H.lookup key obj of Nothing -> fail $ "key " ++ show key ++ " not present"- Just v -> parseJSON v+ Just v -> modifyFailure addKeyName+ $ parseJSON v <?> Key key+ where+ addKeyName = (("failed to parse field " <> unpack key <> ": ") <>) {-# INLINE (.:) #-} -- | Retrieve the value associated with the given key of an 'Object'.@@ -1139,7 +1543,10 @@ (.:?) :: (FromJSON a) => Object -> Text -> Parser (Maybe a) obj .:? key = case H.lookup key obj of Nothing -> pure Nothing- Just v -> parseJSON v+ Just v -> modifyFailure addKeyName+ $ Just <$> parseJSON v <?> Key key+ where+ addKeyName = (("failed to parse field " <> unpack key <> ": ") <>) {-# INLINE (.:?) #-} -- | Helper for use in combination with '.:?' to provide default@@ -1160,28 +1567,18 @@ pmval .!= val = fromMaybe val <$> pmval {-# INLINE (.!=) #-} --- | Fail parsing due to a type mismatch, with a descriptive message.-typeMismatch :: String -- ^ The name of the type you are trying to parse.- -> Value -- ^ The actual value encountered.- -> Parser a-typeMismatch expected actual =- fail $ "when expecting a " ++ expected ++ ", encountered " ++ name ++- " instead"- where- name = case actual of- Object _ -> "Object"- Array _ -> "Array"- String _ -> "String"- Number _ -> "Number"- Bool _ -> "Boolean"- Null -> "Null"- realFloatToJSON :: RealFloat a => a -> Value realFloatToJSON d | isNaN d || isInfinite d = Null | otherwise = Number $ Scientific.fromFloatDigits d {-# INLINE realFloatToJSON #-} +realFloatToEncoding :: RealFloat a => a -> Encoding+realFloatToEncoding d+ | isNaN d || isInfinite d = Encoding E.null_+ | otherwise = toEncoding (Scientific.fromFloatDigits d)+{-# INLINE realFloatToEncoding #-}+ scientificToNumber :: Scientific -> Number scientificToNumber s | e < 0 = D $ Scientific.toRealFloat s@@ -1198,5 +1595,5 @@ {-# INLINE parseRealFloat #-} parseIntegral :: Integral a => String -> Value -> Parser a-parseIntegral expected = withScientific expected $ pure . floor+parseIntegral expected = withScientific expected $ pure . truncate {-# INLINE parseIntegral #-}
Data/Aeson/Types/Internal.hs view
@@ -1,8 +1,9 @@-{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, Rank2Types #-}+{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, Rank2Types,+ RecordWildCards #-} -- | -- Module: Data.Aeson.Types.Internal--- Copyright: (c) 2011, 2012 Bryan O'Sullivan+-- Copyright: (c) 2011-2015 Bryan O'Sullivan -- (c) 2011 MailRank, Inc. -- License: Apache -- Maintainer: Bryan O'Sullivan <bos@serpentine.com>@@ -15,6 +16,8 @@ ( -- * Core JSON types Value(..)+ , Encoding(..)+ , Series(..) , Array , emptyArray, isEmptyArray , Pair@@ -23,10 +26,16 @@ -- * Type conversion , Parser , Result(..)+ , IResult(..)+ , JSONPathElement(..)+ , JSONPath+ , iparse , parse , parseEither , parseMaybe , modifyFailure+ , formatError+ , (<?>) -- * Constructors and accessors , object @@ -38,57 +47,117 @@ -- * Used for changing CamelCase names into something else. , camelTo+ , camelTo2 -- * Other types , DotNetTime(..) ) where - import Control.Applicative-import Control.Monad import Control.DeepSeq (NFData(..))-import Data.Char (toLower, isUpper)-import Data.Scientific (Scientific)-import Data.Hashable (Hashable(..))+import Control.Monad (MonadPlus(..), ap)+import Data.ByteString.Builder (Builder, char7, toLazyByteString)+import Data.Char (isLower, isUpper, toLower) import Data.Data (Data)+import Data.Foldable (Foldable(..)) import Data.HashMap.Strict (HashMap)-import Data.Monoid (Monoid(..))+import Data.Hashable (Hashable(..))+import Data.Monoid (Monoid(..), (<>))+import Data.Scientific (Scientific) import Data.String (IsString(..))-import Data.Text (Text, pack)+import Data.Text (Text, pack, unpack) import Data.Time (UTCTime) import Data.Time.Format (FormatTime)+import Data.Traversable (Traversable(..)) import Data.Typeable (Typeable) import Data.Vector (Vector) import qualified Data.HashMap.Strict as H import qualified Data.Vector as V +-- | Elements of a JSON path used to describe the location of an+-- error.+data JSONPathElement = Key Text+ -- ^ JSON path element of a key into an object,+ -- \"object.key\".+ | Index {-# UNPACK #-} !Int+ -- ^ JSON path element of an index into an+ -- array, \"array[index]\".+ deriving (Eq, Show, Typeable)+type JSONPath = [JSONPathElement]++-- | The internal result of running a 'Parser'.+data IResult a = IError JSONPath String+ | ISuccess a+ deriving (Eq, Show, Typeable)+ -- | The result of running a 'Parser'. data Result a = Error String | Success a deriving (Eq, Show, Typeable) +instance NFData JSONPathElement where+ rnf (Key t) = rnf t+ rnf (Index i) = rnf i++instance (NFData a) => NFData (IResult a) where+ rnf (ISuccess a) = rnf a+ rnf (IError path err) = rnf path `seq` rnf err+ instance (NFData a) => NFData (Result a) where rnf (Success a) = rnf a rnf (Error err) = rnf err +instance Functor IResult where+ fmap f (ISuccess a) = ISuccess (f a)+ fmap _ (IError path err) = IError path err+ {-# INLINE fmap #-}+ instance Functor Result where fmap f (Success a) = Success (f a) fmap _ (Error err) = Error err {-# INLINE fmap #-} +instance Monad IResult where+ return = ISuccess+ {-# INLINE return #-}++ ISuccess a >>= k = k a+ IError path err >>= _ = IError path err+ {-# INLINE (>>=) #-}++ fail err = IError [] err+ {-# INLINE fail #-}+ instance Monad Result where return = Success {-# INLINE return #-}+ Success a >>= k = k a Error err >>= _ = Error err {-# INLINE (>>=) #-} + fail err = Error err+ {-# INLINE fail #-}++instance Applicative IResult where+ pure = return+ {-# INLINE pure #-}+ (<*>) = ap+ {-# INLINE (<*>) #-}+ instance Applicative Result where pure = return {-# INLINE pure #-} (<*>) = ap {-# INLINE (<*>) #-} +instance MonadPlus IResult where+ mzero = fail "mzero"+ {-# INLINE mzero #-}+ mplus a@(ISuccess _) _ = a+ mplus _ b = b+ {-# INLINE mplus #-}+ instance MonadPlus Result where mzero = fail "mzero" {-# INLINE mzero #-}@@ -96,43 +165,84 @@ mplus _ b = b {-# INLINE mplus #-} +instance Alternative IResult where+ empty = mzero+ {-# INLINE empty #-}+ (<|>) = mplus+ {-# INLINE (<|>) #-}+ instance Alternative Result where empty = mzero {-# INLINE empty #-} (<|>) = mplus {-# INLINE (<|>) #-} +instance Monoid (IResult a) where+ mempty = fail "mempty"+ {-# INLINE mempty #-}+ mappend = mplus+ {-# INLINE mappend #-}+ instance Monoid (Result a) where mempty = fail "mempty" {-# INLINE mempty #-} mappend = mplus {-# INLINE mappend #-} +instance Foldable IResult where+ foldMap _ (IError _ _) = mempty+ foldMap f (ISuccess y) = f y+ {-# INLINE foldMap #-}++ foldr _ z (IError _ _) = z+ foldr f z (ISuccess y) = f y z+ {-# INLINE foldr #-}++instance Foldable Result where+ foldMap _ (Error _) = mempty+ foldMap f (Success y) = f y+ {-# INLINE foldMap #-}++ foldr _ z (Error _) = z+ foldr f z (Success y) = f y z+ {-# INLINE foldr #-}++instance Traversable IResult where+ traverse _ (IError path err) = pure (IError path err)+ traverse f (ISuccess a) = ISuccess <$> f a+ {-# INLINE traverse #-}++instance Traversable Result where+ traverse _ (Error err) = pure (Error err)+ traverse f (Success a) = Success <$> f a+ {-# INLINE traverse #-}+ -- | Failure continuation.-type Failure f r = String -> f r+type Failure f r = JSONPath -> String -> f r -- | Success continuation. type Success a f r = a -> f r --- | A continuation-based parser type.+-- | A JSON parser. newtype Parser a = Parser { runParser :: forall f r.- Failure f r+ JSONPath+ -> Failure f r -> Success a f r -> f r } instance Monad Parser where- m >>= g = Parser $ \kf ks -> let ks' a = runParser (g a) kf ks- in runParser m kf ks'+ m >>= g = Parser $ \path kf ks -> let ks' a = runParser (g a) path kf ks+ in runParser m path kf ks' {-# INLINE (>>=) #-}- return a = Parser $ \_kf ks -> ks a+ return a = Parser $ \_path _kf ks -> ks a {-# INLINE return #-}- fail msg = Parser $ \kf _ks -> kf msg+ fail msg = Parser $ \path kf _ks -> kf (reverse path) msg {-# INLINE fail #-} instance Functor Parser where- fmap f m = Parser $ \kf ks -> let ks' a = ks (f a)- in runParser m kf ks'+ fmap f m = Parser $ \path kf ks -> let ks' a = ks (f a)+ in runParser m path kf ks' {-# INLINE fmap #-} instance Applicative Parser where@@ -150,8 +260,8 @@ instance MonadPlus Parser where mzero = fail "mzero" {-# INLINE mzero #-}- mplus a b = Parser $ \kf ks -> let kf' _ = runParser b kf ks- in runParser a kf' ks+ mplus a b = Parser $ \path kf ks -> let kf' _ _ = runParser b path kf ks+ in runParser a path kf' ks {-# INLINE mplus #-} instance Monoid (Parser a) where@@ -182,8 +292,40 @@ | Null deriving (Eq, Read, Show, Typeable, Data) +-- | An encoding of a JSON value.+newtype Encoding = Encoding {+ fromEncoding :: Builder+ -- ^ Acquire the underlying bytestring builder.+ } deriving (Monoid)++instance Show Encoding where+ show (Encoding e) = show (toLazyByteString e)++instance Eq Encoding where+ Encoding a == Encoding b = toLazyByteString a == toLazyByteString b++instance Ord Encoding where+ compare (Encoding a) (Encoding b) =+ compare (toLazyByteString a) (toLazyByteString b)++-- | A series of values that, when encoded, should be separated by commas.+data Series = Empty+ | Value Encoding+ deriving (Typeable)++instance Monoid Series where+ mempty = Empty++ mappend Empty a = a+ mappend (Value a) b =+ Value $+ a <> case b of+ Empty -> mempty+ Value c -> Encoding (char7 ',') <> c+ -- | A newtype wrapper for 'UTCTime' that uses the same non-standard--- serialization format as Microsoft .NET, whose @System.DateTime@+-- serialization format as Microsoft .NET, whose+-- <https://msdn.microsoft.com/en-us/library/system.datetime(v=vs.110).aspx System.DateTime> -- type is by default serialized to JSON as in the following example: -- -- > /Date(1302547608878)/@@ -191,6 +333,7 @@ -- The number represents milliseconds since the Unix epoch. newtype DotNetTime = DotNetTime { fromDotNetTime :: UTCTime+ -- ^ Acquire the underlying value. } deriving (Eq, Ord, Read, Show, Typeable, FormatTime) instance NFData Value where@@ -234,19 +377,35 @@ -- | Run a 'Parser'. parse :: (a -> Parser b) -> a -> Result b-parse m v = runParser (m v) Error Success+parse m v = runParser (m v) [] (const Error) Success {-# INLINE parse #-} +-- | Run a 'Parser'.+iparse :: (a -> Parser b) -> a -> IResult b+iparse m v = runParser (m v) [] IError ISuccess+{-# INLINE iparse #-}+ -- | Run a 'Parser' with a 'Maybe' result type. parseMaybe :: (a -> Parser b) -> a -> Maybe b-parseMaybe m v = runParser (m v) (const Nothing) Just+parseMaybe m v = runParser (m v) [] (\_ _ -> Nothing) Just {-# INLINE parseMaybe #-} --- | Run a 'Parser' with an 'Either' result type.+-- | Run a 'Parser' with an 'Either' result type. If the parse fails,+-- the 'Left' payload will contain an error message. parseEither :: (a -> Parser b) -> a -> Either String b-parseEither m v = runParser (m v) Left Right+parseEither m v = runParser (m v) [] onError Right+ where onError path msg = Left (formatError path msg) {-# INLINE parseEither #-} +-- | Annotate an error message with a+-- <http://goessner.net/articles/JsonPath/ JSONPath> error location.+formatError :: JSONPath -> String -> String+formatError path msg = "Error in " ++ (format "$" path) ++ ": " ++ msg+ where+ format pfx [] = pfx+ format pfx (Index idx:parts) = format (pfx ++ "[" ++ show idx ++ "]") parts+ format pfx (Key key:parts) = format (pfx ++ "." ++ unpack key) parts+ -- | A key\/value pair for an 'Object'. type Pair = (Text, Value) @@ -256,6 +415,24 @@ object = Object . H.fromList {-# INLINE object #-} +-- | Add JSON Path context to a parser+--+-- When parsing complex structure it helps to annotate (sub)parsers+-- with context so that if error occurs you can find it's location.+--+-- > withObject "Person" $ \o ->+-- > Person+-- > <$> o .: "name" <?> Key "name"+-- > <*> o .: "age" <?> Key "age"+--+-- (except for standard methods like '(.:)' already do that)+--+-- After that in case of error you will get a JSON Path location of that error.+--+-- Since 0.9+(<?>) :: Parser a -> JSONPathElement -> Parser a+p <?> pathElem = Parser $ \path kf ks -> runParser p (pathElem:path) kf ks+ -- | If the inner @Parser@ failed, modify the failure message using the -- provided function. This allows you to create more descriptive error messages. -- For example:@@ -266,7 +443,7 @@ -- -- Since 0.6.2.0 modifyFailure :: (String -> String) -> Parser a -> Parser a-modifyFailure f (Parser p) = Parser $ \kf -> p (kf . f)+modifyFailure f (Parser p) = Parser $ \path kf ks -> p path (\p' m -> kf p' (f m)) ks -------------------------------------------------------------------------------- -- Generic and TH encoding configuration@@ -291,8 +468,23 @@ -- object will include those fields mapping to @null@. , sumEncoding :: SumEncoding -- ^ Specifies how to encode constructors of a sum datatype.+ , unwrapUnaryRecords :: Bool+ -- ^ Hide the field name when a record constructor has only one+ -- field, like a newtype. } +instance Show Options where+ show Options{..} = "Options {" +++ "fieldLabelModifier =~ " +++ show (fieldLabelModifier "exampleField") ++ ", " +++ "constructorTagModifier =~ " +++ show (constructorTagModifier "ExampleConstructor") ++ ", " +++ "allNullaryToStringTag = " ++ show allNullaryToStringTag ++ ", " +++ "omitNothingFields = " ++ show omitNothingFields ++ ", " +++ "sumEncoding = " ++ show sumEncoding ++ ", " +++ "unwrapUnaryRecords = " ++ show unwrapUnaryRecords +++ "}"+ -- | Specifies how to encode constructors of a sum datatype. data SumEncoding = TaggedObject { tagFieldName :: String@@ -317,6 +509,7 @@ -- first element is the tag of the constructor (modified by the -- 'constructorTagModifier') and the second element the encoded -- contents of the constructor.+ deriving (Eq, Show) -- | Default encoding 'Options': --@@ -336,6 +529,7 @@ , allNullaryToStringTag = True , omitNothingFields = False , sumEncoding = defaultTaggedObject+ , unwrapUnaryRecords = False } -- | Default 'TaggedObject' 'SumEncoding' options:@@ -361,6 +555,7 @@ -- -- > camelTo '_' 'CamelCaseAPI' == "camel_case_api" camelTo :: Char -> String -> String+{-# DEPRECATED camelTo "Use camelTo2 for better results" #-} camelTo c = lastWasCap True where lastWasCap :: Bool -- ^ Previous was a capital letter@@ -372,3 +567,16 @@ then toLower x : lastWasCap True xs else c : toLower x : lastWasCap True xs else x : lastWasCap False xs++-- | Better version of 'camelTo'. Example where it works better:+--+-- > camelTo '_' 'CamelAPICase' == "camel_apicase"+-- > camelTo2 '_' 'CamelAPICase' == "camel_api_case"+camelTo2 :: Char -> String -> String+camelTo2 c = map toLower . go2 . go1+ where go1 "" = ""+ go1 (x:u:l:xs) | isUpper u && isLower l = x : c : u : l : go1 xs+ go1 (x:xs) = x : go1 xs+ go2 "" = ""+ go2 (l:u:xs) | isLower l && isUpper u = l : c : u : go2 xs+ go2 (x:xs) = x : go2 xs
aeson.cabal view
@@ -1,5 +1,5 @@ name: aeson-version: 0.9.0.1+version: 0.10.0.0 license: BSD3 license-file: LICENSE category: Text, Web, JSON@@ -8,7 +8,7 @@ author: Bryan O'Sullivan <bos@serpentine.com> maintainer: Bryan O'Sullivan <bos@serpentine.com> stability: experimental-tested-with: GHC == 7.4, GHC == 7.6, GHC == 7.8+tested-with: GHC == 7.4, GHC == 7.6, GHC == 7.8, GHC == 7.10 synopsis: Fast JSON parsing and encoding cabal-version: >= 1.8 homepage: https://github.com/bos/aeson@@ -21,41 +21,19 @@ To get started, see the documentation for the @Data.Aeson@ module below. .- Parsing performance on an early 2011 MacBook Pro (2.2GHz Core i7),- running 64-bit GHC 7.6.3, for mostly-English tweets from Twitter's+ Parsing performance on a late 2013 MacBook Pro (2.6GHz Core i7),+ running 64-bit GHC 7.10.1, for mostly-English tweets from Twitter's JSON search API: .- * 0.8 KB: 34124 msg\/sec (27.8 MB\/sec)- .- * 6.4 KB: 6833 msg\/sec (43.0 MB\/sec)- .- * 11.8 KB: 3410 msg\/sec (39.2 MB\/sec)- .- * 31.2 KB: 1157 msg\/sec (35.3 MB\/sec)- .- * 61.5 KB: 542 msg\/sec (32.5 MB\/sec)- .- Handling heavily-escaped text is a little more work. Here is- parsing performance with Japanese tweets, where much of the text- is entirely Unicode-escaped.- .- * 14.6 KB: 2101 msg\/sec (30.0 MB\/sec)- .- * 44.1 KB: 667 msg\/sec (28.7 MB\/sec)+ * 6.4 KB payloads, English: 7570 msg\/sec (47.6 MB\/sec) .- * 82.9 KB: 360 msg\/sec (29.2 MB\/sec)+ * 14.6 KB payloads, Japanese: 3261 msg\/sec (46.6 MB\/sec) . Encoding performance on the same machine and data: .- * English, 0.8 KB: 109697 msg\/sec (89.3 MB\/sec)- .- * English, 6.4 KB: 18517 msg\/sec (116.4 MB\/sec)- .- * Engish, 61.5 KB: 1963 msg\/sec (118.0 MB\/sec)- .- * Japanese, 14.6 KB: 12140 msg\/sec (173.5 MB\/sec)+ * 6.4 KB payloads, English: 22738 msg\/sec (142.9 MB\/sec) .- * Japanese, 44.1 KB: 3980 msg\/sec (171.3 MB\/sec)+ * 14.6 KB payloads, Japanese: 15911 msg\/sec (227.4 MB\/sec) . (A note on naming: in Greek mythology, Aeson was the father of Jason.) @@ -64,10 +42,14 @@ benchmarks/*.cabal benchmarks/*.hs benchmarks/*.py+ benchmarks/Compare/*.hs benchmarks/Makefile+ benchmarks/Typed/*.hs benchmarks/json-data/*.json changelog.md+ examples/*.cabal examples/*.hs+ examples/Twitter/*.hs flag developer description: operate in developer mode@@ -84,23 +66,26 @@ exposed-modules: Data.Aeson Data.Aeson.Encode- Data.Aeson.Generic+ Data.Aeson.Internal+ Data.Aeson.Internal.Time Data.Aeson.Parser Data.Aeson.Types Data.Aeson.TH other-modules:- Data.Aeson.Encode.ByteString+ Data.Aeson.Encode.Builder+ Data.Aeson.Encode.Functions Data.Aeson.Functions Data.Aeson.Parser.Internal+ Data.Aeson.Parser.Time Data.Aeson.Types.Class Data.Aeson.Types.Generic Data.Aeson.Types.Instances Data.Aeson.Types.Internal build-depends:- attoparsec >= 0.13.0.0,- base == 4.*,+ attoparsec >= 0.13.0.1,+ base >= 4.5 && < 5, bytestring >= 0.10.4.0, containers, deepseq,@@ -110,7 +95,7 @@ mtl, scientific >= 0.3.1 && < 0.4, syb,- template-haskell >= 2.4,+ template-haskell >= 2.7, text >= 1.1.1.0, transformers, unordered-containers >= 0.2.5.0,@@ -126,26 +111,27 @@ ghc-prof-options: -auto-all ghc-options: -O2 -Wall- cpp-options: -DGENERICS test-suite tests type: exitcode-stdio-1.0 hs-source-dirs: tests- main-is: Properties.hs+ main-is: Tests.hs other-modules:+ DataFamilies.Encoders+ DataFamilies.Types Encoders Functions Instances Options- Properties.Deprecated+ Properties Types+ UnitTests ghc-options: -Wall -threaded -rtsopts- cpp-options: -DGHC_GENERICS build-depends: HUnit,- QuickCheck,+ QuickCheck >= 2.7, aeson, attoparsec, base,
benchmarks/AesonEncode.hs view
@@ -3,7 +3,7 @@ import Control.Exception import Control.Monad import Data.Aeson-import Data.Attoparsec (IResult(..), parseWith)+import Data.Attoparsec.ByteString (IResult(..), parseWith) import Data.Char (isDigit) import Data.Time.Clock import System.Environment (getArgs)
benchmarks/AesonParse.hs view
@@ -3,7 +3,7 @@ import Control.Exception import Control.Monad import Data.Aeson-import Data.Attoparsec (IResult(..), parseWith)+import Data.Attoparsec.ByteString (IResult(..), parseWith) import Data.Time.Clock import System.Environment (getArgs) import System.IO
+ benchmarks/Compare.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE ScopedTypeVariables #-}++module Main (main) where++import Compare.BufferBuilder ()+import Compare.JsonBuilder ()+import Criterion.Main+import Data.BufferBuilder.Json+import Data.Json.Builder+import Twitter+import Twitter.Manual ()+import Typed.Common+import qualified Compare.JsonBench as JsonBench+import qualified Data.Aeson as Aeson++main :: IO ()+main =+ defaultMain [+ env (load "json-data/twitter100.json") $ \ ~(twtr :: Result) ->+ bgroup "twitter" [+ bench "aeson" $ nf Aeson.encode twtr+ , bench "buffer-builder" $ nf encodeJson twtr+ , bench "json-builder" $ nf toJsonLBS twtr+ ]+ , JsonBench.benchmarks+ ]
+ benchmarks/Compare/BufferBuilder.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE OverloadedStrings, RecordWildCards #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Compare.BufferBuilder () where++import Data.BufferBuilder.Json+import Data.Monoid ((<>))+import Data.Int (Int64)+import Prelude hiding (id)+import Twitter+import qualified Data.BufferBuilder.Utf8 as UB++instance (ToJson a, ToJson b) => ToJson (a,b) where+ toJson (a,b) = array [toJson a, toJson b]++instance ToJson Int64 where+ toJson a = unsafeValueUtf8Builder $+ UB.appendDecimalSignedInt (fromIntegral a)+ {-# INLINE toJson #-}++instance ToJson Metadata where+ toJson Metadata{..} = toJson $+ "result_type" .= result_type++instance ToJson Geo where+ toJson Geo{..} = toJson $+ "type_" .= type_+ <> "coordinates" .= coordinates++instance ToJson Story where+ toJson Story{..} = toJson $+ "from_user_id_str" .= from_user_id_str+ <> "profile_image_url" .= profile_image_url+ <> "created_at" .= created_at+ <> "from_user" .= from_user+ <> "id_str" .= id_str+ <> "metadata" .= metadata+ <> "to_user_id" .= to_user_id+ <> "text" .= text+ <> "id" .= id+ <> "from_user_id" .= from_user_id+ <> "geo" .= geo+ <> "iso_language_code" .= iso_language_code+ <> "to_user_id_str" .= to_user_id_str+ <> "source" .= source++instance ToJson Result where+ toJson Result{..} = toJson $+ "results" .= results+ <> "max_id" .= max_id+ <> "since_id" .= since_id+ <> "refresh_url" .= refresh_url+ <> "next_page" .= next_page+ <> "results_per_page" .= results_per_page+ <> "page" .= page+ <> "completed_in" .= completed_in+ <> "since_id_str" .= since_id_str+ <> "max_id_str" .= max_id_str+ <> "query" .= query
+ benchmarks/Compare/JsonBench.hs view
@@ -0,0 +1,325 @@+-- Adapted from a buffer-builder benchmark:+--+-- https://github.com/chadaustin/buffer-builder/blob/master/test.json++{-# LANGUAGE BangPatterns, OverloadedStrings, RecordWildCards #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MagicHash, ScopedTypeVariables #-}++module Compare.JsonBench (benchmarks) where++import Control.DeepSeq (NFData(..))+import Criterion+import Data.Aeson ((.:))+import Data.Monoid ((<>))+import Data.Text (Text)+import Typed.Common (load)+import qualified Data.Aeson as Aeson+import qualified Data.BufferBuilder.Json as Json+import qualified Data.Json.Builder as JB++data EyeColor = Green | Blue | Brown+ deriving (Eq, Show)+data Gender = Male | Female+ deriving (Eq, Show)+data Fruit = Apple | Strawberry | Banana+ deriving (Eq, Show)+data Friend = Friend+ { fId :: !Int+ , fName :: !Text+ } deriving (Eq, Show)++data User = User+ { uId :: !Text+ , uIndex :: !Int+ , uGuid :: !Text+ , uIsActive :: !Bool+ , uBalance :: !Text+ , uPicture :: !Text+ , uAge :: !Int+ , uEyeColor :: !EyeColor+ , uName :: !Text+ , uGender :: !Gender+ , uCompany :: !Text+ , uEmail :: !Text+ , uPhone :: !Text+ , uAddress :: !Text+ , uAbout :: !Text+ , uRegistered :: !Text -- UTCTime?+ , uLatitude :: !Double+ , uLongitude :: !Double+ , uTags :: ![Text]+ , uFriends :: ![Friend]+ , uGreeting :: !Text+ , uFavouriteFruit :: !Fruit+ } deriving (Eq, Show)++instance NFData EyeColor where rnf !_ = ()+instance NFData Gender where rnf !_ = ()+instance NFData Fruit where rnf !_ = ()++instance NFData Friend where+ rnf Friend {..} = (rnf fId) `seq` (rnf fName) `seq` ()++instance NFData User where+ rnf User {..} = (rnf uId) `seq` (rnf uIndex) `seq` (rnf uGuid) `seq` (rnf uIsActive) `seq` (rnf uBalance) `seq` (rnf uPicture) `seq` (rnf uAge) `seq` (rnf uEyeColor) `seq` (rnf uName) `seq` (rnf uGender) `seq` (rnf uCompany) `seq` (rnf uEmail) `seq` (rnf uPhone) `seq` (rnf uAddress) `seq` (rnf uAbout) `seq` (rnf uRegistered) `seq` (rnf uLatitude) `seq` (rnf uLongitude) `seq` (rnf uTags) `seq` (rnf uFriends) `seq` (rnf uGreeting) `seq` (rnf uFavouriteFruit) `seq` ()++eyeColorTable :: [(Text, EyeColor)]+eyeColorTable = [("brown", Brown), ("green", Green), ("blue", Blue)]++genderTable :: [(Text, Gender)]+genderTable = [("male", Male), ("female", Female)]++fruitTable :: [(Text, Fruit)]+fruitTable = [("apple", Apple), ("strawberry", Strawberry), ("banana", Banana)]++enumFromJson :: Monad m => String -> [(Text, enum)] -> (json -> m Text) -> json -> m enum+enumFromJson enumName table extract v = do+ s <- extract v+ case lookup s table of+ Just r -> return r+ Nothing -> fail $ "Bad " ++ enumName ++ ": " ++ show s++--- Aeson instances ---++instance Aeson.FromJSON EyeColor where+ parseJSON = enumFromJson "EyeColor" eyeColorTable Aeson.parseJSON++instance Aeson.FromJSON Gender where+ parseJSON = enumFromJson "Gender" genderTable Aeson.parseJSON++instance Aeson.FromJSON Fruit where+ parseJSON = enumFromJson "Fruit" fruitTable Aeson.parseJSON++instance Aeson.FromJSON Friend where+ parseJSON = Aeson.withObject "Friend" $ \o -> do+ fId <- o .: "id"+ fName <- o .: "name"+ return Friend {..}++instance Aeson.FromJSON User where+ parseJSON = Aeson.withObject "User" $ \o -> do+ uId <- o .: "_id"+ uIndex <- o .: "index"+ uGuid <- o .: "guid"+ uIsActive <- o .: "isActive"+ uBalance <- o .: "balance"+ uPicture <- o .: "picture"+ uAge <- o .: "age"+ uEyeColor <- o .: "eyeColor"+ uName <- o .: "name"+ uGender <- o .: "gender"+ uCompany <- o .: "company"+ uEmail <- o .: "email"+ uPhone <- o .: "phone"+ uAddress <- o .: "address"+ uAbout <- o .: "about"+ uRegistered <- o .: "registered"+ uLatitude <- o .: "latitude"+ uLongitude <- o .: "longitude"+ uTags <- o .: "tags"+ uFriends <- o .: "friends"+ uGreeting <- o .: "greeting"+ uFavouriteFruit <- o .: "favoriteFruit"+ return User {..}++instance Aeson.ToJSON EyeColor where+ toJSON ec = Aeson.toJSON $ case ec of+ Green -> "green" :: Text+ Blue -> "blue"+ Brown -> "brown"++ toEncoding ec = Aeson.toEncoding $ case ec of+ Green -> "green" :: Text+ Blue -> "blue"+ Brown -> "brown"++instance Aeson.ToJSON Gender where+ toJSON g = Aeson.toJSON $ case g of+ Male -> "male" :: Text+ Female -> "female"++ toEncoding g = Aeson.toEncoding $ case g of+ Male -> "male" :: Text+ Female -> "female"++instance Aeson.ToJSON Fruit where+ toJSON f = Aeson.toJSON $ case f of+ Apple -> "apple" :: Text+ Banana -> "banana"+ Strawberry -> "strawberry"++ toEncoding f = Aeson.toEncoding $ case f of+ Apple -> "apple" :: Text+ Banana -> "banana"+ Strawberry -> "strawberry"++instance Aeson.ToJSON Friend where+ toJSON Friend {..} = Aeson.object+ [ "id" Aeson..= fId+ , "name" Aeson..= fName+ ]++ toEncoding Friend {..} = Aeson.pairs $+ "id" Aeson..= fId+ <> "name" Aeson..= fName++instance Aeson.ToJSON User where+ toJSON User{..} = Aeson.object+ [ "_id" Aeson..= uId+ , "index" Aeson..= uIndex+ , "guid" Aeson..= uGuid+ , "isActive" Aeson..= uIsActive+ , "balance" Aeson..= uBalance+ , "picture" Aeson..= uPicture+ , "age" Aeson..= uAge+ , "eyeColor" Aeson..= uEyeColor+ , "name" Aeson..= uName+ , "gender" Aeson..= uGender+ , "company" Aeson..= uCompany+ , "email" Aeson..= uEmail+ , "phone" Aeson..= uPhone+ , "address" Aeson..= uAddress+ , "about" Aeson..= uAbout+ , "registered" Aeson..= uRegistered+ , "latitude" Aeson..= uLatitude+ , "longitude" Aeson..= uLongitude+ , "tags" Aeson..= uTags+ , "friends" Aeson..= uFriends+ , "greeting" Aeson..= uGreeting+ , "favoriteFruit" Aeson..= uFavouriteFruit+ ]++ toEncoding User{..} = Aeson.pairs $+ "_id" Aeson..= uId+ <> "index" Aeson..= uIndex+ <> "guid" Aeson..= uGuid+ <> "isActive" Aeson..= uIsActive+ <> "balance" Aeson..= uBalance+ <> "picture" Aeson..= uPicture+ <> "age" Aeson..= uAge+ <> "eyeColor" Aeson..= uEyeColor+ <> "name" Aeson..= uName+ <> "gender" Aeson..= uGender+ <> "company" Aeson..= uCompany+ <> "email" Aeson..= uEmail+ <> "phone" Aeson..= uPhone+ <> "address" Aeson..= uAddress+ <> "about" Aeson..= uAbout+ <> "registered" Aeson..= uRegistered+ <> "latitude" Aeson..= uLatitude+ <> "longitude" Aeson..= uLongitude+ <> "tags" Aeson..= uTags+ <> "friends" Aeson..= uFriends+ <> "greeting" Aeson..= uGreeting+ <> "favoriteFruit" Aeson..= uFavouriteFruit++--- BufferBuilder instances ---++instance Json.ToJson EyeColor where+ toJson ec = Json.toJson $ case ec of+ Green -> "green" :: Text+ Blue -> "blue"+ Brown -> "brown"++instance Json.ToJson Gender where+ toJson g = Json.toJson $ case g of+ Male -> "male" :: Text+ Female -> "female"++instance Json.ToJson Fruit where+ toJson f = Json.toJson $ case f of+ Apple -> "apple" :: Text+ Strawberry -> "strawberry"+ Banana -> "banana"++instance Json.ToJson Friend where+ toJson Friend{..} = Json.toJson $+ "_id" Json..= fId+ <> "name" Json..= fName++instance Json.ToJson User where+ toJson User{..} = Json.toJson $+ "_id"# Json..=# uId+ <> "index"# Json..=# uIndex+ <> "guid"# Json..=# uGuid+ <> "isActive"# Json..=# uIsActive+ <> "balance"# Json..=# uBalance+ <> "picture"# Json..=# uPicture+ <> "age"# Json..=# uAge+ <> "eyeColor"# Json..=# uEyeColor+ <> "name"# Json..=# uName+ <> "gender"# Json..=# uGender+ <> "company"# Json..=# uCompany+ <> "email"# Json..=# uEmail+ <> "phone"# Json..=# uPhone+ <> "address"# Json..=# uAddress+ <> "about"# Json..=# uAbout+ <> "registered"# Json..=# uRegistered+ <> "latitude"# Json..=# uLatitude+ <> "longitude"# Json..=# uLongitude+ <> "tags"# Json..=# uTags+ <> "friends"# Json..=# uFriends+ <> "greeting"# Json..=# uGreeting+ <> "favoriteFruit"# Json..=# uFavouriteFruit++---- json-builder instances ----++instance JB.Value EyeColor where+ toJson ec = JB.toJson $ case ec of+ Green -> "green" :: Text+ Blue -> "blue"+ Brown -> "brown"++instance JB.Value Gender where+ toJson g = JB.toJson $ case g of+ Male -> "male" :: Text+ Female -> "female"++instance JB.Value Fruit where+ toJson f = JB.toJson $ case f of+ Apple -> "apple" :: Text+ Strawberry -> "strawberry"+ Banana -> "banana"++instance JB.Value Friend where+ toJson Friend{..} = JB.toJson $+ ("_id" :: Text) `JB.row` fId+ <> ("name" :: Text) `JB.row` fName++instance JB.Value User where+ toJson User{..} =+ let t :: Text -> Text+ t = id+ in JB.toJson $+ t "_id" `JB.row` uId+ <> t "index" `JB.row` uIndex+ <> t "guid" `JB.row` uGuid+ <> t "isActive" `JB.row` uIsActive+ <> t "balance" `JB.row` uBalance+ <> t "picture" `JB.row` uPicture+ <> t "age" `JB.row` uAge+ <> t "eyeColor" `JB.row` uEyeColor+ <> t "name" `JB.row` uName+ <> t "gender" `JB.row` uGender+ <> t "company" `JB.row` uCompany+ <> t "email" `JB.row` uEmail+ <> t "phone" `JB.row` uPhone+ <> t "address" `JB.row` uAddress+ <> t "about" `JB.row` uAbout+ <> t "registered" `JB.row` uRegistered+ <> t "latitude" `JB.row` uLatitude+ <> t "longitude" `JB.row` uLongitude+ <> t "tags" `JB.row` uTags+ <> t "friends" `JB.row` uFriends+ <> t "greeting" `JB.row` uGreeting+ <> t "favoriteFruit" `JB.row` uFavouriteFruit++benchmarks :: Benchmark+benchmarks = env (load "json-data/buffer-builder.json") $+ \ ~(parsedUserList :: [User]) ->+ bgroup "json-bench" [+ bench "aeson" $ nf Aeson.encode parsedUserList+ , bench "buffer-builder" $ nf Json.encodeJson parsedUserList+ , bench "json-builder" $ nf JB.toJsonLBS parsedUserList+ ]
+ benchmarks/Compare/JsonBuilder.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE RecordWildCards #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Compare.JsonBuilder () where++import Data.Json.Builder+import Data.Monoid ((<>))+import Prelude hiding (id)+import Twitter++instance JsObject Metadata where+ toObject Metadata{..} = row "result_type" result_type++instance Value Metadata where+ toJson = toJson . toObject++instance JsObject Geo where+ toObject Geo{..} =+ row "type_" type_ <>+ row "coordinates" coordinates++instance Value Geo where+ toJson = toJson . toObject++instance Value a => Value (Maybe a) where+ toJson (Just a) = toJson a+ toJson Nothing = jsNull++instance JsObject Story where+ toObject Story{..} =+ row "from_user_id_str" from_user_id_str <>+ row "profile_image_url" profile_image_url <>+ row "created_at" created_at <>+ row "from_user" from_user <>+ row "id_str" id_str <>+ row "metadata" metadata <>+ row "to_user_id" to_user_id <>+ row "text" text <>+ row "id" id <>+ row "from_user_id" from_user_id <>+ row "geo" geo <>+ row "iso_language_code" iso_language_code <>+ row "to_user_id_str" to_user_id_str <>+ row "source" source++instance Value Story where+ toJson = toJson . toObject++instance JsObject Result where+ toObject Result{..} =+ row "results" results <>+ row "max_id" max_id <>+ row "since_id" since_id <>+ row "refresh_url" refresh_url <>+ row "next_page" next_page <>+ row "results_per_page" results_per_page <>+ row "page" page <>+ row "completed_in" completed_in <>+ row "since_id_str" since_id_str <>+ row "max_id_str" max_id_str <>+ row "query" query++instance Value Result where+ toJson = toJson . toObject
benchmarks/CompareWithJSON.hs view
@@ -34,6 +34,11 @@ Just v -> v Nothing -> error "fail to parse via Aeson" +decodeA' :: BL.ByteString -> A.Value+decodeA' s = case A.decode' s of+ Just v -> v+ Nothing -> error "fail to parse via Aeson"+ encodeJ :: J.JSValue -> BL.ByteString encodeJ = toLazyByteString . fromString . J.encode @@ -54,7 +59,8 @@ defaultMain [ bgroup "decode" [ bgroup "en" [- bench "aeson" $ nf decodeA enA+ bench "aeson/lazy" $ nf decodeA enA+ , bench "aeson/strict" $ nf decodeA' enA , bench "json" $ nf decodeJ enJ ] , bgroup "jp" [
+ benchmarks/Dates.hs view
@@ -0,0 +1,39 @@+import Control.Applicative ((<$>))+import Criterion.Main+import Data.Aeson (decode, encode)+import Data.Time.Clock (UTCTime)+import Data.Time.LocalTime (ZonedTime)+import qualified Data.ByteString.Lazy as BL++utcTime :: BL.ByteString -> Maybe [UTCTime]+utcTime = decode++zTime :: BL.ByteString -> Maybe [ZonedTime]+zTime = decode++main :: IO ()+main = do+ let file1 = BL.readFile "json-data/dates.json"+ let file2 = BL.readFile "json-data/dates-fract.json"+ defaultMain [+ bgroup "decode" [+ bgroup "UTCTime" [+ env file1 $ \ ~bs -> bench "whole" $ nf utcTime bs+ , env file2 $ \ ~bs -> bench "fractional" $ nf utcTime bs+ ]+ , bgroup "ZonedTime" [+ env file1 $ \ ~bs -> bench "whole" $ nf zTime bs+ , env file2 $ \ ~bs -> bench "fractional" $ nf zTime bs+ ]+ ]+ , bgroup "encode" [+ bgroup "UTCTime" [+ env (utcTime <$> file1) $ \ ~ts -> bench "whole" $ nf encode ts+ , env (utcTime <$> file2) $ \ ~ts -> bench "fractional" $ nf encode ts+ ]+ , bgroup "ZonedTime" [+ env (zTime <$> file1) $ \ ~ts -> bench "whole" $ nf encode ts+ , env (zTime <$> file2) $ \ ~ts -> bench "fractional" $ nf encode ts+ ]+ ]+ ]
+ benchmarks/Micro.hs view
@@ -0,0 +1,18 @@+module Main (main) where++import Criterion.Main+import qualified Data.Aeson.Encode.Builder as AB+import qualified Data.ByteString.Builder as B+import qualified Data.Text as T+++main :: IO ()+main = do+ let txt = "append (append b (primBounded w1 x1)) (primBounded w2 x2)"+ defaultMain [+ bgroup "string" [+ bench "text" $ nf (B.toLazyByteString . AB.text) (T.pack txt)+ , bench "string direct" $ nf (B.toLazyByteString . AB.string) txt+ , bench "string via text" $ nf (B.toLazyByteString . AB.text . T.pack) txt+ ]+ ]
+ benchmarks/Typed.hs view
@@ -0,0 +1,13 @@+module Main (main) where++import Criterion.Main+import qualified Typed.Generic as Generic+import qualified Typed.Manual as Manual+import qualified Typed.TH as TH++main :: IO ()+main = defaultMain [+ Generic.benchmarks+ , Manual.benchmarks+ , TH.benchmarks+ ]
+ benchmarks/Typed/Common.hs view
@@ -0,0 +1,16 @@+module Typed.Common (load) where++import Data.Aeson hiding (Result)+import Data.ByteString.Lazy as L+import Control.Applicative+import System.IO+import System.Exit++load :: FromJSON a => FilePath -> IO a+load fileName = do+ mv <- eitherDecode' <$> L.readFile fileName+ case mv of+ Right v -> return v+ Left err -> do+ hPutStrLn stderr $ fileName ++ ": JSON decode failed - " ++ err+ exitWith (ExitFailure 1)
+ benchmarks/Typed/Generic.hs view
@@ -0,0 +1,29 @@+module Typed.Generic (benchmarks) where++import Control.Applicative+import Criterion+import Data.Aeson hiding (Result)+import Data.ByteString.Builder as B+import Data.ByteString.Lazy as L+import Twitter.TH+import Typed.Common++encodeDirect :: Result -> L.ByteString+encodeDirect = encode++encodeViaValue :: Result -> L.ByteString+encodeViaValue = encode . toJSON++benchmarks :: Benchmark+benchmarks =+ env ((,) <$> load "json-data/twitter100.json" <*> load "json-data/jp100.json") $ \ ~(twitter100, jp100) ->+ bgroup "generic" [+ bgroup "direct" [+ bench "twitter100" $ nf encodeDirect twitter100+ , bench "jp100" $ nf encodeDirect jp100+ ]+ , bgroup "viaValue" [+ bench "twitter100" $ nf encodeViaValue twitter100+ , bench "jp100" $ nf encodeViaValue jp100+ ]+ ]
+ benchmarks/Typed/Manual.hs view
@@ -0,0 +1,29 @@+module Typed.Manual (benchmarks) where++import Control.Applicative+import Criterion+import Data.Aeson hiding (Result)+import Data.ByteString.Builder as B+import Data.ByteString.Lazy as L+import Twitter.Manual+import Typed.Common++encodeDirect :: Result -> L.ByteString+encodeDirect = encode++encodeViaValue :: Result -> L.ByteString+encodeViaValue = encode . toJSON++benchmarks :: Benchmark+benchmarks =+ env ((,) <$> load "json-data/twitter100.json" <*> load "json-data/jp100.json") $ \ ~(twitter100, jp100) ->+ bgroup "manual" [+ bgroup "direct" [+ bench "twitter100" $ nf encodeDirect twitter100+ , bench "jp100" $ nf encodeDirect jp100+ ]+ , bgroup "viaValue" [+ bench "twitter100" $ nf encodeViaValue twitter100+ , bench "jp100" $ nf encodeViaValue jp100+ ]+ ]
+ benchmarks/Typed/TH.hs view
@@ -0,0 +1,29 @@+module Typed.TH (benchmarks) where++import Control.Applicative+import Criterion+import Data.Aeson hiding (Result)+import Data.ByteString.Builder as B+import Data.ByteString.Lazy as L+import Twitter.TH+import Typed.Common++encodeDirect :: Result -> L.ByteString+encodeDirect = encode++encodeViaValue :: Result -> L.ByteString+encodeViaValue = encode . toJSON++benchmarks :: Benchmark+benchmarks =+ env ((,) <$> load "json-data/twitter100.json" <*> load "json-data/jp100.json") $ \ ~(twitter100, jp100) ->+ bgroup "th" [+ bgroup "direct" [+ bench "twitter100" $ nf encodeDirect twitter100+ , bench "jp100" $ nf encodeDirect jp100+ ]+ , bgroup "viaValue" [+ bench "twitter100" $ nf encodeViaValue twitter100+ , bench "jp100" $ nf encodeViaValue jp100+ ]+ ]
benchmarks/aeson-benchmarks.cabal view
@@ -11,27 +11,28 @@ default: False library- hs-source-dirs: ..+ hs-source-dirs: .. . exposed-modules: Data.Aeson Data.Aeson.Encode- Data.Aeson.Generic- Data.Aeson.Parser- Data.Aeson.Types- Data.Aeson.TH-- other-modules:- Data.Aeson.Encode.ByteString+ Data.Aeson.Encode.Builder+ Data.Aeson.Encode.Functions Data.Aeson.Functions+ Data.Aeson.Internal+ Data.Aeson.Internal.Time+ Data.Aeson.Parser Data.Aeson.Parser.Internal+ Data.Aeson.Parser.Time+ Data.Aeson.TH+ Data.Aeson.Types Data.Aeson.Types.Class Data.Aeson.Types.Generic Data.Aeson.Types.Instances Data.Aeson.Types.Internal build-depends:- attoparsec >= 0.13.0.0,+ attoparsec >= 0.13.0.1, base == 4.*, bytestring >= 0.10.4.0, containers,@@ -44,6 +45,7 @@ syb, template-haskell >= 2.4, text >= 1.1.1.0,+ time, transformers, unordered-containers >= 0.2.3.0, vector >= 0.7.1@@ -56,6 +58,48 @@ ghc-options: -O2 -Wall cpp-options: -DGENERICS +executable aeson-benchmark-compare+ main-is: Compare.hs+ hs-source-dirs: ../examples .+ ghc-options: -Wall -O2 -rtsopts+ build-depends:+ aeson-benchmarks,+ base,+ buffer-builder,+ bytestring,+ criterion >= 1.0,+ deepseq,+ ghc-prim,+ json-builder,+ text++executable aeson-benchmark-micro+ main-is: Micro.hs+ hs-source-dirs: ../examples .+ ghc-options: -Wall -O2 -rtsopts+ build-depends:+ aeson-benchmarks,+ base,+ bytestring,+ criterion >= 1.0,+ deepseq,+ ghc-prim,+ text++executable aeson-benchmark-typed+ main-is: Typed.hs+ hs-source-dirs: ../examples .+ ghc-options: -Wall -O2 -rtsopts+ build-depends:+ aeson-benchmarks,+ base,+ bytestring,+ criterion >= 1.0,+ deepseq,+ ghc-prim,+ text,+ time+ executable aeson-benchmark-compare-with-json main-is: CompareWithJSON.hs ghc-options: -Wall -O2 -rtsopts@@ -97,4 +141,16 @@ base, deepseq, json,+ time++executable aeson-benchmark-dates+ main-is: Dates.hs+ ghc-options: -Wall -O2 -rtsopts+ build-depends:+ base,+ bytestring,+ criterion,+ deepseq,+ aeson-benchmarks,+ text, time
+ benchmarks/json-data/buffer-builder.json view
@@ -0,0 +1,4322 @@+[+ {+ "_id": "54727a90e43524efe8abfdac",+ "index": 0,+ "guid": "aaa926e8-8359-4afe-adb0-dca0401de765",+ "isActive": true,+ "balance": "$1,114.73",+ "picture": "http://placehold.it/32x32",+ "age": 20,+ "eyeColor": "green",+ "name": "Dillon Valenzuela",+ "gender": "male",+ "company": "GEOFORM",+ "email": "dillonvalenzuela@geoform.com",+ "phone": "+1 (817) 536-3796",+ "address": "309 Desmond Court, Zarephath, Montana, 6156",+ "about": "Dolore laboris excepteur sunt velit velit nostrud non esse qui laboris nostrud Lorem. Amet anim occaecat et ipsum. Ad proident nostrud elit adipisicing anim labore consectetur ut amet elit. Tempor aliqua in ea eiusmod elit Lorem cillum est laboris. Nisi Lorem amet amet Lorem. Nostrud sunt incididunt magna nostrud amet enim. Laboris ad et fugiat dolor ad proident aliquip nisi do ea eiusmod enim proident.\r\n",+ "registered": "2014-08-17T07:29:03 +07:00",+ "latitude": -17.423462,+ "longitude": 121.069662,+ "tags": [+ "sunt",+ "ex",+ "irure",+ "cillum",+ "velit",+ "duis",+ "sit"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Joyce Jordan"+ },+ {+ "id": 1,+ "name": "Ophelia Rosales"+ },+ {+ "id": 2,+ "name": "Florine Stark"+ }+ ],+ "greeting": "Hello, Dillon Valenzuela! You have 9 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90f520a07ff2498a69",+ "index": 1,+ "guid": "8f78cc18-a7ef-498b-9adf-60f008a48c02",+ "isActive": false,+ "balance": "$1,324.52",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "blue",+ "name": "Donovan Weiss",+ "gender": "male",+ "company": "TELPOD",+ "email": "donovanweiss@telpod.com",+ "phone": "+1 (962) 417-2408",+ "address": "511 Grant Avenue, Westmoreland, Hawaii, 5092",+ "about": "Laborum excepteur exercitation sint veniam dolor. Dolor aliqua esse do aliqua adipisicing. Ea magna minim veniam tempor ipsum. Incididunt anim reprehenderit occaecat proident eiusmod anim Lorem aliquip dolore incididunt. Consequat occaecat qui minim commodo est velit ex.\r\n",+ "registered": "2014-09-30T23:49:41 +07:00",+ "latitude": -18.034963,+ "longitude": 70.821705,+ "tags": [+ "cupidatat",+ "excepteur",+ "id",+ "consectetur",+ "ea",+ "enim",+ "et"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Cummings Irwin"+ },+ {+ "id": 1,+ "name": "Conley Lester"+ },+ {+ "id": 2,+ "name": "Katy Holt"+ }+ ],+ "greeting": "Hello, Donovan Weiss! You have 2 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90fbb3f49ea6d40dde",+ "index": 2,+ "guid": "69a4c6d7-6189-4a90-ae00-7b64ab1d5a2d",+ "isActive": false,+ "balance": "$2,739.87",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "brown",+ "name": "Renee Calderon",+ "gender": "female",+ "company": "TALKOLA",+ "email": "reneecalderon@talkola.com",+ "phone": "+1 (910) 523-3382",+ "address": "323 Montauk Avenue, Greenwich, South Dakota, 8034",+ "about": "Reprehenderit deserunt et do proident Lorem Lorem dolor labore ullamco eu nulla laborum voluptate. Consectetur sint magna enim commodo dolore ullamco in. Nulla id proident esse veniam proident esse velit exercitation do. Qui nulla magna anim Lorem dolor culpa id. Nostrud cupidatat officia culpa sit irure voluptate exercitation voluptate nostrud elit. Duis occaecat velit fugiat exercitation anim aute laborum irure.\r\n",+ "registered": "2014-09-11T20:48:20 +07:00",+ "latitude": 15.654081,+ "longitude": 84.156609,+ "tags": [+ "dolor",+ "et",+ "in",+ "veniam",+ "non",+ "est",+ "enim"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Gilda Murray"+ },+ {+ "id": 1,+ "name": "Marguerite West"+ },+ {+ "id": 2,+ "name": "Chrystal Rojas"+ }+ ],+ "greeting": "Hello, Renee Calderon! You have 1 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90c5ea2a48502a0640",+ "index": 3,+ "guid": "689a64d7-16b0-41dc-947d-035b40a29ed4",+ "isActive": false,+ "balance": "$3,805.39",+ "picture": "http://placehold.it/32x32",+ "age": 32,+ "eyeColor": "blue",+ "name": "Aguirre Garrett",+ "gender": "male",+ "company": "ZOSIS",+ "email": "aguirregarrett@zosis.com",+ "phone": "+1 (811) 471-3145",+ "address": "198 Baycliff Terrace, Clarence, District Of Columbia, 1528",+ "about": "Deserunt minim aliquip magna ut fugiat quis. Quis consequat culpa reprehenderit minim do eiusmod adipisicing nostrud aute. Lorem nostrud laborum quis dolore tempor tempor magna aute eu pariatur dolor est. Reprehenderit ex consectetur adipisicing Lorem nostrud fugiat aute non quis anim laborum aute proident amet. Sunt consectetur eu ut eu mollit ipsum.\r\n",+ "registered": "2014-02-14T04:27:27 +08:00",+ "latitude": 25.922024,+ "longitude": 107.428199,+ "tags": [+ "esse",+ "officia",+ "commodo",+ "esse",+ "cupidatat",+ "amet",+ "ad"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Penelope Humphrey"+ },+ {+ "id": 1,+ "name": "Church Byers"+ },+ {+ "id": 2,+ "name": "Hazel Stafford"+ }+ ],+ "greeting": "Hello, Aguirre Garrett! You have 4 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a9096bcf2d2f4b4aeff",+ "index": 4,+ "guid": "77392422-81ad-48c8-9cfc-37d142a814d5",+ "isActive": false,+ "balance": "$1,956.06",+ "picture": "http://placehold.it/32x32",+ "age": 26,+ "eyeColor": "brown",+ "name": "Griffin Mclaughlin",+ "gender": "male",+ "company": "COMTOUR",+ "email": "griffinmclaughlin@comtour.com",+ "phone": "+1 (950) 494-2956",+ "address": "549 Robert Street, Libertytown, North Carolina, 4377",+ "about": "Exercitation culpa ad id deserunt sit ullamco anim anim ad aute officia ut tempor. Ullamco dolor pariatur enim exercitation commodo consectetur fugiat velit nulla mollit pariatur occaecat. Amet voluptate qui labore mollit ipsum consequat. Esse pariatur proident ad pariatur aliquip labore quis voluptate quis ut culpa tempor. Reprehenderit sint id officia deserunt quis laboris. Velit ipsum dolore anim consectetur.\r\n",+ "registered": "2014-06-23T04:48:12 +07:00",+ "latitude": 8.808284,+ "longitude": 20.539814,+ "tags": [+ "consequat",+ "proident",+ "eiusmod",+ "dolore",+ "in",+ "laborum",+ "non"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Hinton Santiago"+ },+ {+ "id": 1,+ "name": "Talley Dyer"+ },+ {+ "id": 2,+ "name": "Karen Logan"+ }+ ],+ "greeting": "Hello, Griffin Mclaughlin! You have 3 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a9010e5c5ac55919561",+ "index": 5,+ "guid": "7e6fca4d-0329-47ab-b3e7-f4d6a6ee4dd2",+ "isActive": true,+ "balance": "$3,767.46",+ "picture": "http://placehold.it/32x32",+ "age": 36,+ "eyeColor": "brown",+ "name": "Rachel Mcclure",+ "gender": "female",+ "company": "ESCENTA",+ "email": "rachelmcclure@escenta.com",+ "phone": "+1 (857) 518-3454",+ "address": "901 Harwood Place, Rossmore, Tennessee, 3213",+ "about": "Nisi enim deserunt ut ex mollit fugiat. Magna nostrud culpa irure nulla mollit nisi. Sit ea incididunt amet culpa veniam voluptate Lorem sunt dolore amet. Exercitation tempor eiusmod exercitation officia dolor. Ut ea sint veniam cupidatat et. Sunt nostrud ad ipsum non elit elit esse ut dolor. Et officia et minim ipsum amet sint eu ut nostrud adipisicing cillum ullamco.\r\n",+ "registered": "2014-05-29T20:42:11 +07:00",+ "latitude": 8.132878,+ "longitude": -99.198755,+ "tags": [+ "est",+ "Lorem",+ "ullamco",+ "nisi",+ "reprehenderit",+ "nisi",+ "cupidatat"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Michael Martin"+ },+ {+ "id": 1,+ "name": "Gayle Heath"+ },+ {+ "id": 2,+ "name": "Slater Bender"+ }+ ],+ "greeting": "Hello, Rachel Mcclure! You have 2 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90a76a5ba627b180c9",+ "index": 6,+ "guid": "fbf59485-142c-4eb6-a98e-8952cbb19942",+ "isActive": true,+ "balance": "$2,139.12",+ "picture": "http://placehold.it/32x32",+ "age": 28,+ "eyeColor": "blue",+ "name": "Megan Morrow",+ "gender": "female",+ "company": "PETICULAR",+ "email": "meganmorrow@peticular.com",+ "phone": "+1 (825) 572-2854",+ "address": "151 Jardine Place, Boonville, Idaho, 160",+ "about": "Magna reprehenderit aliqua quis eiusmod eu minim ut. Consectetur non veniam est et aliqua mollit. Aliqua eiusmod sit fugiat qui quis nisi mollit officia do. Enim quis quis occaecat ullamco anim reprehenderit exercitation. Ad id id laborum ipsum ipsum cillum ipsum occaecat irure. Commodo voluptate ullamco excepteur ea laboris adipisicing veniam cillum commodo velit anim. Occaecat magna laborum non ex anim consequat dolor cillum excepteur velit duis commodo officia veniam.\r\n",+ "registered": "2014-04-16T08:56:52 +07:00",+ "latitude": 57.771446,+ "longitude": -146.885322,+ "tags": [+ "veniam",+ "officia",+ "magna",+ "ipsum",+ "nulla",+ "ea",+ "mollit"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Marina Wise"+ },+ {+ "id": 1,+ "name": "Ann Mercado"+ },+ {+ "id": 2,+ "name": "Glenn Duran"+ }+ ],+ "greeting": "Hello, Megan Morrow! You have 7 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90776f7328f4df750f",+ "index": 7,+ "guid": "ef99cc91-061c-49c5-9901-3ac22a75bc92",+ "isActive": true,+ "balance": "$3,161.69",+ "picture": "http://placehold.it/32x32",+ "age": 37,+ "eyeColor": "blue",+ "name": "Lawson Kirby",+ "gender": "male",+ "company": "PLASMOSIS",+ "email": "lawsonkirby@plasmosis.com",+ "phone": "+1 (853) 583-2577",+ "address": "122 Linden Boulevard, Edneyville, Palau, 6050",+ "about": "Elit ullamco reprehenderit eiusmod in duis minim exercitation incididunt reprehenderit eiusmod nulla. Cupidatat ea anim incididunt esse ea eu esse laboris velit. Culpa sunt exercitation officia amet voluptate enim duis ipsum ex anim quis nisi. Dolor officia irure do veniam do amet ullamco eu.\r\n",+ "registered": "2014-08-13T02:14:13 +07:00",+ "latitude": -16.166232,+ "longitude": 12.254111,+ "tags": [+ "et",+ "aliqua",+ "aute",+ "voluptate",+ "officia",+ "est",+ "quis"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Marquita Hutchinson"+ },+ {+ "id": 1,+ "name": "Karla Conner"+ },+ {+ "id": 2,+ "name": "Mattie Page"+ }+ ],+ "greeting": "Hello, Lawson Kirby! You have 3 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90b8e9fff0ed297a59",+ "index": 8,+ "guid": "9bb8d813-704c-4714-929f-1321576a2701",+ "isActive": false,+ "balance": "$1,275.37",+ "picture": "http://placehold.it/32x32",+ "age": 23,+ "eyeColor": "brown",+ "name": "Pat Medina",+ "gender": "female",+ "company": "PLEXIA",+ "email": "patmedina@plexia.com",+ "phone": "+1 (933) 557-3028",+ "address": "623 Sunnyside Court, Edinburg, Minnesota, 2620",+ "about": "Est aliqua sint adipisicing labore magna sunt laboris non eu. Aute deserunt commodo Lorem amet sunt amet qui qui incididunt anim Lorem culpa. Ea exercitation officia dolor aute incididunt ea enim. Nulla aliqua ut ullamco sunt velit cillum esse minim incididunt ut mollit aute. Fugiat eiusmod anim laborum duis aliquip aute reprehenderit qui dolor officia amet labore id. Enim officia reprehenderit incididunt sit. Nisi ullamco nisi adipisicing esse eiusmod dolore veniam cupidatat consequat sunt.\r\n",+ "registered": "2014-10-22T20:29:14 +07:00",+ "latitude": -9.032987,+ "longitude": 71.98971,+ "tags": [+ "laborum",+ "dolore",+ "aliqua",+ "tempor",+ "eu",+ "elit",+ "voluptate"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Elnora Moses"+ },+ {+ "id": 1,+ "name": "Alexandra Carter"+ },+ {+ "id": 2,+ "name": "Beth Pacheco"+ }+ ],+ "greeting": "Hello, Pat Medina! You have 5 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a908c17a619571cfd39",+ "index": 9,+ "guid": "0a5de094-eadc-4120-8941-964f27fbc898",+ "isActive": true,+ "balance": "$1,939.34",+ "picture": "http://placehold.it/32x32",+ "age": 35,+ "eyeColor": "brown",+ "name": "Gibbs Butler",+ "gender": "male",+ "company": "OPTIQUE",+ "email": "gibbsbutler@optique.com",+ "phone": "+1 (956) 574-3434",+ "address": "552 Columbia Street, Richmond, Illinois, 903",+ "about": "Laboris eu ut magna exercitation non laboris sint. Mollit velit est exercitation enim exercitation reprehenderit culpa eiusmod laboris fugiat veniam adipisicing. Voluptate enim id do eu officia duis in incididunt. Esse do laboris pariatur cupidatat elit.\r\n",+ "registered": "2014-02-24T15:46:23 +08:00",+ "latitude": -68.874573,+ "longitude": -6.876165,+ "tags": [+ "excepteur",+ "deserunt",+ "ea",+ "labore",+ "aliqua",+ "deserunt",+ "labore"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Chen Langley"+ },+ {+ "id": 1,+ "name": "Latonya Vaughan"+ },+ {+ "id": 2,+ "name": "Simone Sutton"+ }+ ],+ "greeting": "Hello, Gibbs Butler! You have 2 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a9049447027a378812c",+ "index": 10,+ "guid": "406ae437-820d-4e0f-b8dc-1da0ddcc561c",+ "isActive": false,+ "balance": "$1,348.37",+ "picture": "http://placehold.it/32x32",+ "age": 39,+ "eyeColor": "brown",+ "name": "Bond Peck",+ "gender": "male",+ "company": "DANCERITY",+ "email": "bondpeck@dancerity.com",+ "phone": "+1 (918) 554-2856",+ "address": "361 Cortelyou Road, Hollins, Missouri, 131",+ "about": "Nisi ut ea ut deserunt. Consequat pariatur dolor consequat sunt. Ullamco aute proident excepteur fugiat id consequat eu nisi occaecat.\r\n",+ "registered": "2014-05-15T02:12:14 +07:00",+ "latitude": -79.266187,+ "longitude": 92.89454,+ "tags": [+ "ex",+ "est",+ "sit",+ "irure",+ "qui",+ "veniam",+ "exercitation"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Nettie Pope"+ },+ {+ "id": 1,+ "name": "Alyssa Hensley"+ },+ {+ "id": 2,+ "name": "Puckett Kinney"+ }+ ],+ "greeting": "Hello, Bond Peck! You have 7 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a9062a82eff9506c4d7",+ "index": 11,+ "guid": "b7400b79-2b71-46cd-9260-13e0767b437e",+ "isActive": true,+ "balance": "$1,757.66",+ "picture": "http://placehold.it/32x32",+ "age": 20,+ "eyeColor": "blue",+ "name": "Garrison Warner",+ "gender": "male",+ "company": "NAMEBOX",+ "email": "garrisonwarner@namebox.com",+ "phone": "+1 (874) 417-2183",+ "address": "927 Knapp Street, Shaft, Connecticut, 2188",+ "about": "Sint commodo ipsum commodo id magna labore in. Pariatur nostrud reprehenderit adipisicing amet enim ut quis laboris culpa exercitation deserunt cillum. Adipisicing excepteur sunt do labore anim exercitation non excepteur. Minim consectetur sit dolore occaecat et aliquip aliquip excepteur aliquip ut do eiusmod ea nulla. Nostrud sunt dolore ea sunt est enim occaecat culpa minim. Sit elit mollit mollit aliquip eu ex. Tempor nulla voluptate dolore ex.\r\n",+ "registered": "2014-06-18T03:58:19 +07:00",+ "latitude": -87.629414,+ "longitude": 96.653639,+ "tags": [+ "eu",+ "deserunt",+ "dolore",+ "nisi",+ "culpa",+ "ullamco",+ "ipsum"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Gutierrez Sears"+ },+ {+ "id": 1,+ "name": "Holly Jacobson"+ },+ {+ "id": 2,+ "name": "Henry Delgado"+ }+ ],+ "greeting": "Hello, Garrison Warner! You have 4 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a904638f48ca7f9e85e",+ "index": 12,+ "guid": "4cd59615-46b7-4733-a439-dc59c0ca0118",+ "isActive": true,+ "balance": "$3,897.06",+ "picture": "http://placehold.it/32x32",+ "age": 24,+ "eyeColor": "blue",+ "name": "Consuelo Bray",+ "gender": "female",+ "company": "COMTEST",+ "email": "consuelobray@comtest.com",+ "phone": "+1 (945) 432-2620",+ "address": "433 Clinton Street, Clarktown, Maine, 6916",+ "about": "Do occaecat consectetur tempor Lorem ullamco commodo exercitation veniam reprehenderit nulla officia. Nisi irure sunt cupidatat amet et excepteur quis et do. Et commodo nulla occaecat do sint quis mollit reprehenderit do laboris magna. Dolore ea sit aute esse consequat fugiat Lorem occaecat adipisicing adipisicing qui aute elit. Amet veniam anim ipsum aute officia. Fugiat nisi magna anim pariatur minim magna exercitation duis officia.\r\n",+ "registered": "2014-03-19T07:39:44 +07:00",+ "latitude": 7.760448,+ "longitude": -92.399314,+ "tags": [+ "irure",+ "veniam",+ "ex",+ "ullamco",+ "anim",+ "do",+ "enim"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Ellen Bullock"+ },+ {+ "id": 1,+ "name": "Davis Vaughn"+ },+ {+ "id": 2,+ "name": "Robert Mendoza"+ }+ ],+ "greeting": "Hello, Consuelo Bray! You have 8 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90fd85a45d33d54cf7",+ "index": 13,+ "guid": "53868eb7-df5c-445d-ad62-6124db081b6c",+ "isActive": false,+ "balance": "$2,988.04",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "green",+ "name": "Clark Skinner",+ "gender": "male",+ "company": "OVOLO",+ "email": "clarkskinner@ovolo.com",+ "phone": "+1 (834) 587-2391",+ "address": "967 Dewey Place, Gibsonia, Puerto Rico, 6398",+ "about": "Duis irure exercitation ullamco amet aliquip minim sit consequat officia laborum id ad. Lorem duis velit consequat non irure nulla elit elit velit dolor ullamco qui fugiat. Quis ad velit ea consectetur veniam Lorem incididunt quis magna eiusmod. Et nostrud irure tempor nostrud esse.\r\n",+ "registered": "2014-10-11T06:48:59 +07:00",+ "latitude": -62.633073,+ "longitude": -121.03338,+ "tags": [+ "ut",+ "deserunt",+ "adipisicing",+ "enim",+ "amet",+ "proident",+ "officia"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Francine Petersen"+ },+ {+ "id": 1,+ "name": "Lena Robles"+ },+ {+ "id": 2,+ "name": "Mcintyre Gardner"+ }+ ],+ "greeting": "Hello, Clark Skinner! You have 6 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a908789850c55818269",+ "index": 14,+ "guid": "84cc7d0b-0544-40f8-900a-825429b0ee87",+ "isActive": true,+ "balance": "$3,012.07",+ "picture": "http://placehold.it/32x32",+ "age": 32,+ "eyeColor": "blue",+ "name": "Katie Allen",+ "gender": "female",+ "company": "SYBIXTEX",+ "email": "katieallen@sybixtex.com",+ "phone": "+1 (959) 504-2563",+ "address": "543 Heath Place, Bartonsville, New Mexico, 4882",+ "about": "Nisi ullamco anim in culpa in non nostrud ex aliqua ex. Nisi occaecat exercitation sint ad magna Lorem amet anim pariatur quis. Dolore consequat quis dolor ea. Aliquip sunt ex cillum tempor fugiat laboris ipsum mollit aliqua reprehenderit nulla fugiat exercitation ad.\r\n",+ "registered": "2014-03-17T05:45:50 +07:00",+ "latitude": -79.18988,+ "longitude": -95.023826,+ "tags": [+ "commodo",+ "incididunt",+ "voluptate",+ "sit",+ "mollit",+ "veniam",+ "et"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Hampton Jimenez"+ },+ {+ "id": 1,+ "name": "Lara Cline"+ },+ {+ "id": 2,+ "name": "Jennings Cantu"+ }+ ],+ "greeting": "Hello, Katie Allen! You have 3 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90787015f61850162f",+ "index": 15,+ "guid": "d848ac32-1d24-471a-ad7e-d272f52cb5fc",+ "isActive": true,+ "balance": "$1,416.33",+ "picture": "http://placehold.it/32x32",+ "age": 38,+ "eyeColor": "brown",+ "name": "Pratt Watson",+ "gender": "male",+ "company": "HARMONEY",+ "email": "prattwatson@harmoney.com",+ "phone": "+1 (905) 557-3197",+ "address": "867 Campus Road, Lindisfarne, Northern Mariana Islands, 8349",+ "about": "Nisi mollit eu reprehenderit qui ut eu cillum cupidatat do. Et ex qui minim proident. Quis aliquip aliquip exercitation exercitation dolor aute nostrud fugiat ea. Id ullamco occaecat reprehenderit mollit occaecat ea ipsum cupidatat ea consequat fugiat.\r\n",+ "registered": "2014-11-15T05:07:03 +08:00",+ "latitude": -66.117872,+ "longitude": 52.197654,+ "tags": [+ "ullamco",+ "sunt",+ "ea",+ "veniam",+ "elit",+ "sint",+ "id"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Dale Ray"+ },+ {+ "id": 1,+ "name": "Beryl Hayes"+ },+ {+ "id": 2,+ "name": "Millie Good"+ }+ ],+ "greeting": "Hello, Pratt Watson! You have 2 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90c4106283f0c1eed9",+ "index": 16,+ "guid": "6839b0af-5c69-45e2-b83b-381ff05034e6",+ "isActive": false,+ "balance": "$2,720.67",+ "picture": "http://placehold.it/32x32",+ "age": 31,+ "eyeColor": "blue",+ "name": "Shari Mendez",+ "gender": "female",+ "company": "INDEXIA",+ "email": "sharimendez@indexia.com",+ "phone": "+1 (895) 589-3754",+ "address": "533 Conduit Boulevard, Forestburg, Mississippi, 6873",+ "about": "Ex excepteur elit id laborum veniam dolore duis ea eiusmod minim. Consequat reprehenderit magna elit tempor voluptate esse officia minim reprehenderit consequat fugiat qui eiusmod. Et Lorem nisi voluptate tempor nulla cillum reprehenderit pariatur elit dolore occaecat laboris sunt. Anim cupidatat do veniam pariatur nostrud anim eu aliqua veniam ad cillum quis.\r\n",+ "registered": "2014-05-04T10:15:37 +07:00",+ "latitude": 31.931465,+ "longitude": 155.732674,+ "tags": [+ "enim",+ "sint",+ "est",+ "aliqua",+ "elit",+ "laboris",+ "occaecat"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Desiree Norris"+ },+ {+ "id": 1,+ "name": "Abigail Crosby"+ },+ {+ "id": 2,+ "name": "Anderson Alston"+ }+ ],+ "greeting": "Hello, Shari Mendez! You have 6 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90474ecbf0a9c34382",+ "index": 17,+ "guid": "079bb238-0556-4ede-8243-2eaadabb3050",+ "isActive": false,+ "balance": "$2,629.01",+ "picture": "http://placehold.it/32x32",+ "age": 26,+ "eyeColor": "green",+ "name": "Hancock Rowland",+ "gender": "male",+ "company": "SOFTMICRO",+ "email": "hancockrowland@softmicro.com",+ "phone": "+1 (983) 565-2302",+ "address": "168 Dooley Street, Driftwood, North Dakota, 3607",+ "about": "Eu voluptate velit incididunt ipsum amet veniam. Lorem aliquip adipisicing incididunt laborum aliqua elit consectetur aute velit voluptate ea. Mollit irure duis consequat veniam sint nostrud est dolore sunt anim laboris fugiat. Dolor officia elit esse elit dolore. Minim non est duis culpa ullamco veniam excepteur. Veniam ullamco amet ullamco esse voluptate laboris velit.\r\n",+ "registered": "2014-09-06T04:32:40 +07:00",+ "latitude": -68.853851,+ "longitude": 135.592762,+ "tags": [+ "nulla",+ "ut",+ "magna",+ "adipisicing",+ "officia",+ "nulla",+ "cillum"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Shannon Burch"+ },+ {+ "id": 1,+ "name": "Marisol Nixon"+ },+ {+ "id": 2,+ "name": "Poole Wolfe"+ }+ ],+ "greeting": "Hello, Hancock Rowland! You have 4 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90cf708eccc9032fd0",+ "index": 18,+ "guid": "8930775e-9271-400e-b662-77ee520b3369",+ "isActive": false,+ "balance": "$1,026.68",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "blue",+ "name": "Luna Rice",+ "gender": "male",+ "company": "GEEKULAR",+ "email": "lunarice@geekular.com",+ "phone": "+1 (840) 541-2996",+ "address": "417 Varick Avenue, Martell, Vermont, 2749",+ "about": "Aliqua enim ullamco do eiusmod. Ipsum incididunt minim esse veniam nisi velit. Ipsum reprehenderit velit eiusmod nisi magna dolore consectetur reprehenderit magna culpa. Commodo excepteur labore proident adipisicing in velit sit occaecat reprehenderit id.\r\n",+ "registered": "2014-10-15T05:13:55 +07:00",+ "latitude": -57.335675,+ "longitude": -173.387514,+ "tags": [+ "fugiat",+ "enim",+ "exercitation",+ "aliquip",+ "Lorem",+ "laboris",+ "deserunt"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Mclaughlin Schmidt"+ },+ {+ "id": 1,+ "name": "Munoz Key"+ },+ {+ "id": 2,+ "name": "Candace Stephenson"+ }+ ],+ "greeting": "Hello, Luna Rice! You have 2 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90a0fd17c9e4f5d33f",+ "index": 19,+ "guid": "570f0e20-085f-4c40-9e84-b555cc4e79c8",+ "isActive": true,+ "balance": "$3,333.73",+ "picture": "http://placehold.it/32x32",+ "age": 39,+ "eyeColor": "green",+ "name": "Beverly Newton",+ "gender": "female",+ "company": "ECLIPSENT",+ "email": "beverlynewton@eclipsent.com",+ "phone": "+1 (902) 595-3072",+ "address": "903 Knight Court, Gardiner, Rhode Island, 3327",+ "about": "Labore culpa tempor nisi commodo dolore exercitation est eu. Aute exercitation duis proident deserunt culpa ullamco. Irure cillum elit ea sint dolore ipsum adipisicing anim sit. Amet incididunt labore ex fugiat mollit quis reprehenderit nisi ut excepteur proident ullamco laboris. Reprehenderit voluptate aliqua labore culpa in non magna velit nostrud amet. Minim nulla ea culpa irure. Minim ea ex nisi proident ex ex quis ipsum culpa.\r\n",+ "registered": "2014-09-23T10:25:17 +07:00",+ "latitude": 23.973865,+ "longitude": -71.604537,+ "tags": [+ "ullamco",+ "anim",+ "id",+ "pariatur",+ "est",+ "cupidatat",+ "qui"+ ],+ "friends": [+ {+ "id": 0,+ "name": "James Garner"+ },+ {+ "id": 1,+ "name": "Goff Reese"+ },+ {+ "id": 2,+ "name": "Casey Bradford"+ }+ ],+ "greeting": "Hello, Beverly Newton! You have 2 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90fd0cafc2fa513aea",+ "index": 20,+ "guid": "c0e243a3-bf20-4112-8dab-0b0aed785060",+ "isActive": true,+ "balance": "$2,290.97",+ "picture": "http://placehold.it/32x32",+ "age": 28,+ "eyeColor": "blue",+ "name": "Stokes Dodson",+ "gender": "male",+ "company": "SLAMBDA",+ "email": "stokesdodson@slambda.com",+ "phone": "+1 (994) 443-2829",+ "address": "232 Kosciusko Street, Manitou, Michigan, 2638",+ "about": "Nostrud minim cillum elit reprehenderit ut do eu. Quis deserunt enim nisi do proident quis quis voluptate elit. Sit nostrud et amet nostrud pariatur exercitation cillum ullamco laborum ullamco do id. Tempor incididunt dolore consequat ut amet in reprehenderit magna anim laboris reprehenderit tempor adipisicing.\r\n",+ "registered": "2014-05-21T16:30:03 +07:00",+ "latitude": -86.112825,+ "longitude": 56.089279,+ "tags": [+ "ea",+ "dolor",+ "dolor",+ "consequat",+ "nulla",+ "cillum",+ "voluptate"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Jodi Camacho"+ },+ {+ "id": 1,+ "name": "Michele Miles"+ },+ {+ "id": 2,+ "name": "Rene Mitchell"+ }+ ],+ "greeting": "Hello, Stokes Dodson! You have 9 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a908be67242a33d9597",+ "index": 21,+ "guid": "8ad92a47-ac1d-46ad-9dc3-d1f96526bf1d",+ "isActive": true,+ "balance": "$1,134.78",+ "picture": "http://placehold.it/32x32",+ "age": 20,+ "eyeColor": "green",+ "name": "Jody Stewart",+ "gender": "female",+ "company": "EARGO",+ "email": "jodystewart@eargo.com",+ "phone": "+1 (925) 470-3426",+ "address": "271 Norwood Avenue, Sperryville, Oklahoma, 9504",+ "about": "Ut cillum ea pariatur Lorem ad veniam ex ullamco. Exercitation culpa sit occaecat aliquip eu quis magna exercitation quis reprehenderit nostrud consequat. Exercitation magna duis culpa nulla id proident. Adipisicing sunt consequat laborum consequat id dolore aute qui. Consectetur magna irure minim ut consectetur elit qui elit voluptate sint excepteur officia.\r\n",+ "registered": "2014-04-29T09:04:08 +07:00",+ "latitude": -51.736959,+ "longitude": -37.406481,+ "tags": [+ "officia",+ "ullamco",+ "velit",+ "nulla",+ "ipsum",+ "eiusmod",+ "mollit"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Jodie Browning"+ },+ {+ "id": 1,+ "name": "Collins Gamble"+ },+ {+ "id": 2,+ "name": "Emerson Mccullough"+ }+ ],+ "greeting": "Hello, Jody Stewart! You have 4 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a905956037e359d6786",+ "index": 22,+ "guid": "730467a3-9f5d-4d41-9503-09f30222dffa",+ "isActive": false,+ "balance": "$1,821.23",+ "picture": "http://placehold.it/32x32",+ "age": 24,+ "eyeColor": "brown",+ "name": "Wall Moss",+ "gender": "male",+ "company": "BOILICON",+ "email": "wallmoss@boilicon.com",+ "phone": "+1 (865) 518-2689",+ "address": "902 Fleet Street, Cornfields, West Virginia, 9088",+ "about": "Consectetur voluptate enim est elit dolor adipisicing reprehenderit ut in proident sunt. Fugiat cillum anim ullamco qui laborum sit. Dolore qui mollit ut irure proident consequat est veniam. Qui incididunt quis duis enim quis cupidatat do nostrud dolore labore consectetur laboris consectetur. Adipisicing veniam amet officia mollit incididunt non veniam ea laboris. Enim adipisicing velit in dolore proident Lorem esse et sunt.\r\n",+ "registered": "2014-01-21T18:36:59 +08:00",+ "latitude": -70.265889,+ "longitude": -148.213176,+ "tags": [+ "ea",+ "cillum",+ "ea",+ "enim",+ "aliqua",+ "nostrud",+ "do"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Margaret Chavez"+ },+ {+ "id": 1,+ "name": "Mendez Garrison"+ },+ {+ "id": 2,+ "name": "Howard Ortiz"+ }+ ],+ "greeting": "Hello, Wall Moss! You have 9 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a9062feb6c7bfa8710d",+ "index": 23,+ "guid": "1b428a55-1b50-4bcf-b2d9-06c2e8950768",+ "isActive": true,+ "balance": "$1,045.36",+ "picture": "http://placehold.it/32x32",+ "age": 25,+ "eyeColor": "blue",+ "name": "Adele Santana",+ "gender": "female",+ "company": "EBIDCO",+ "email": "adelesantana@ebidco.com",+ "phone": "+1 (981) 528-2138",+ "address": "117 Kent Avenue, Chamizal, Iowa, 4289",+ "about": "Culpa eu nostrud mollit voluptate consequat pariatur. Qui ex laboris velit cupidatat enim. Reprehenderit commodo eu excepteur ex elit amet dolore enim. Nisi dolor pariatur enim laborum voluptate Lorem magna ipsum enim aute do sunt. Ad consectetur velit laborum magna labore Lorem occaecat quis. Exercitation ipsum velit nostrud cupidatat consequat ex non velit deserunt pariatur officia. Magna occaecat Lorem qui aliqua id aliquip laborum.\r\n",+ "registered": "2014-10-01T21:15:54 +07:00",+ "latitude": 24.339451,+ "longitude": -38.920718,+ "tags": [+ "ullamco",+ "labore",+ "magna",+ "fugiat",+ "consectetur",+ "nostrud",+ "veniam"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Sharpe Haley"+ },+ {+ "id": 1,+ "name": "Patrice Horne"+ },+ {+ "id": 2,+ "name": "Melanie Sosa"+ }+ ],+ "greeting": "Hello, Adele Santana! You have 10 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a900e0eec7c0c194713",+ "index": 24,+ "guid": "cc7114a5-89ce-4fb6-9ad8-b5886360ab42",+ "isActive": true,+ "balance": "$2,505.31",+ "picture": "http://placehold.it/32x32",+ "age": 36,+ "eyeColor": "blue",+ "name": "Lindsey Colon",+ "gender": "male",+ "company": "XYLAR",+ "email": "lindseycolon@xylar.com",+ "phone": "+1 (952) 532-3896",+ "address": "144 Poly Place, Detroit, Federated States Of Micronesia, 2004",+ "about": "Ullamco nostrud Lorem duis duis aute sunt commodo Lorem. Esse cupidatat aliqua et laborum officia et. Ea magna est eiusmod id sit ea esse consectetur qui.\r\n",+ "registered": "2014-04-05T02:52:07 +07:00",+ "latitude": -55.350071,+ "longitude": -20.446672,+ "tags": [+ "id",+ "sit",+ "cillum",+ "id",+ "exercitation",+ "reprehenderit",+ "deserunt"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Kathleen Berger"+ },+ {+ "id": 1,+ "name": "Morales Tran"+ },+ {+ "id": 2,+ "name": "Dionne Hunter"+ }+ ],+ "greeting": "Hello, Lindsey Colon! You have 3 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90a20ec5bce57f2f55",+ "index": 25,+ "guid": "c1d3f95b-25dd-4b48-8fe8-9af5f62895e2",+ "isActive": true,+ "balance": "$1,609.28",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "green",+ "name": "Langley Moore",+ "gender": "male",+ "company": "ZYTRAX",+ "email": "langleymoore@zytrax.com",+ "phone": "+1 (912) 580-3688",+ "address": "747 Abbey Court, Odessa, Kentucky, 4688",+ "about": "Eiusmod adipisicing aliquip quis voluptate qui. Enim esse culpa elit id eu dolor culpa eiusmod. Deserunt ut ea ipsum ipsum non culpa ullamco non ipsum sunt cupidatat.\r\n",+ "registered": "2014-06-28T08:29:15 +07:00",+ "latitude": 65.464748,+ "longitude": -129.638837,+ "tags": [+ "deserunt",+ "cillum",+ "sint",+ "proident",+ "ad",+ "adipisicing",+ "mollit"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Mcguire Vance"+ },+ {+ "id": 1,+ "name": "Norma Buck"+ },+ {+ "id": 2,+ "name": "Janelle Bailey"+ }+ ],+ "greeting": "Hello, Langley Moore! You have 8 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a903c9a63ef7fccce96",+ "index": 26,+ "guid": "88c32c0f-a2c6-49c2-8261-bc323895067f",+ "isActive": false,+ "balance": "$3,748.41",+ "picture": "http://placehold.it/32x32",+ "age": 26,+ "eyeColor": "blue",+ "name": "Duran Bryan",+ "gender": "male",+ "company": "BULLZONE",+ "email": "duranbryan@bullzone.com",+ "phone": "+1 (911) 598-2827",+ "address": "903 Village Road, Cressey, New Jersey, 9174",+ "about": "Do in fugiat est deserunt in sit Lorem quis reprehenderit est ut tempor. Ullamco in veniam non quis cillum consectetur id. Elit exercitation reprehenderit et amet voluptate magna voluptate minim veniam enim exercitation aute aute esse. Exercitation magna voluptate laborum ipsum cupidatat exercitation ad eu aute deserunt et. Voluptate qui aute ut elit amet excepteur nostrud officia irure do.\r\n",+ "registered": "2014-01-29T12:32:05 +08:00",+ "latitude": -51.269785,+ "longitude": 79.015891,+ "tags": [+ "consequat",+ "id",+ "exercitation",+ "incididunt",+ "adipisicing",+ "laboris",+ "laboris"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Jenny Allison"+ },+ {+ "id": 1,+ "name": "Della Hobbs"+ },+ {+ "id": 2,+ "name": "Bradshaw Owens"+ }+ ],+ "greeting": "Hello, Duran Bryan! You have 5 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a907a2f07fbb3efec0f",+ "index": 27,+ "guid": "df997a84-5ec1-4f63-acb7-140b9fed981d",+ "isActive": true,+ "balance": "$1,249.61",+ "picture": "http://placehold.it/32x32",+ "age": 28,+ "eyeColor": "blue",+ "name": "Juarez House",+ "gender": "male",+ "company": "ZUVY",+ "email": "juarezhouse@zuvy.com",+ "phone": "+1 (841) 533-3140",+ "address": "494 Atlantic Avenue, Shasta, Nevada, 8475",+ "about": "Proident eu nostrud laboris adipisicing pariatur sint ipsum exercitation velit non incididunt. Qui cupidatat reprehenderit nostrud magna sunt aute nulla aliquip velit culpa commodo fugiat laborum. Dolore consectetur esse labore magna anim exercitation dolor velit qui sunt Lorem reprehenderit amet.\r\n",+ "registered": "2014-03-16T19:21:13 +07:00",+ "latitude": 57.96486,+ "longitude": 130.460435,+ "tags": [+ "incididunt",+ "reprehenderit",+ "consequat",+ "duis",+ "veniam",+ "nulla",+ "dolor"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Keri Lara"+ },+ {+ "id": 1,+ "name": "Celina Pace"+ },+ {+ "id": 2,+ "name": "Bush Haynes"+ }+ ],+ "greeting": "Hello, Juarez House! You have 7 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a903021f42c063be598",+ "index": 28,+ "guid": "1dc6349d-4354-42a9-9f73-7bc12d5ac9c2",+ "isActive": false,+ "balance": "$1,991.33",+ "picture": "http://placehold.it/32x32",+ "age": 26,+ "eyeColor": "blue",+ "name": "Sonja Horton",+ "gender": "female",+ "company": "VIDTO",+ "email": "sonjahorton@vidto.com",+ "phone": "+1 (990) 504-2432",+ "address": "612 River Street, Carrizo, California, 5778",+ "about": "Nisi reprehenderit occaecat anim ut minim aliqua aliquip velit veniam eiusmod reprehenderit laboris ad. Duis aliqua labore cillum proident est amet. Adipisicing nostrud proident labore laborum. Elit est sint ex veniam reprehenderit. Veniam ut dolor nulla tempor voluptate sit excepteur sit ut quis.\r\n",+ "registered": "2014-10-30T05:07:28 +07:00",+ "latitude": 85.37031,+ "longitude": -122.082636,+ "tags": [+ "tempor",+ "ex",+ "nostrud",+ "ullamco",+ "ullamco",+ "nisi",+ "cillum"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Phillips Henry"+ },+ {+ "id": 1,+ "name": "Leanne Sexton"+ },+ {+ "id": 2,+ "name": "Alisha Chang"+ }+ ],+ "greeting": "Hello, Sonja Horton! You have 1 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a903a33ff6bb03e049a",+ "index": 29,+ "guid": "4ef3a65d-5407-400b-aace-62bbb8a83c6a",+ "isActive": true,+ "balance": "$2,823.03",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "blue",+ "name": "Lidia Hewitt",+ "gender": "female",+ "company": "PROWASTE",+ "email": "lidiahewitt@prowaste.com",+ "phone": "+1 (909) 562-3312",+ "address": "625 Ralph Avenue, Kiskimere, Maryland, 2033",+ "about": "Eu adipisicing eiusmod laboris veniam sunt id ad eiusmod consectetur nisi. Esse nulla ipsum Lorem nisi consequat laborum. Veniam ea exercitation ullamco pariatur consectetur. Cupidatat velit excepteur ex eu sunt id. In velit reprehenderit pariatur velit. Voluptate nostrud deserunt qui mollit et tempor nostrud eiusmod adipisicing ad est laborum. Fugiat nisi sit nulla eu ad.\r\n",+ "registered": "2014-01-15T00:05:42 +08:00",+ "latitude": -50.566931,+ "longitude": -149.036259,+ "tags": [+ "in",+ "ipsum",+ "tempor",+ "magna",+ "aliqua",+ "duis",+ "incididunt"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Allie Baker"+ },+ {+ "id": 1,+ "name": "Valdez Giles"+ },+ {+ "id": 2,+ "name": "Knox Vargas"+ }+ ],+ "greeting": "Hello, Lidia Hewitt! You have 3 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90ce7ef56e53f98790",+ "index": 30,+ "guid": "9ae34b38-098b-4de6-aa0f-90359571ddf2",+ "isActive": false,+ "balance": "$3,152.82",+ "picture": "http://placehold.it/32x32",+ "age": 38,+ "eyeColor": "brown",+ "name": "Nieves Ewing",+ "gender": "male",+ "company": "QNEKT",+ "email": "nievesewing@qnekt.com",+ "phone": "+1 (888) 460-2384",+ "address": "425 Highland Place, Hampstead, Washington, 7019",+ "about": "Ipsum aliquip ullamco labore aliquip et. Eu pariatur exercitation ex fugiat fugiat. Nulla voluptate et cupidatat deserunt mollit et incididunt. Deserunt anim qui cupidatat veniam et et dolore qui sunt tempor ipsum. In et voluptate excepteur incididunt dolore cupidatat exercitation ullamco dolore Lorem nostrud sunt nostrud. Occaecat amet ut laborum laborum aliqua est incididunt ea excepteur commodo. Ipsum et elit nisi duis pariatur occaecat.\r\n",+ "registered": "2014-06-15T18:44:29 +07:00",+ "latitude": 8.010315,+ "longitude": 69.049129,+ "tags": [+ "exercitation",+ "eiusmod",+ "voluptate",+ "ullamco",+ "consectetur",+ "reprehenderit",+ "enim"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Maggie Rodriguez"+ },+ {+ "id": 1,+ "name": "Evans Roach"+ },+ {+ "id": 2,+ "name": "Greer Mccoy"+ }+ ],+ "greeting": "Hello, Nieves Ewing! You have 7 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a9049aa4bbedefd311d",+ "index": 31,+ "guid": "471d52a6-da38-4015-8d7a-6fe215a032d3",+ "isActive": false,+ "balance": "$1,456.93",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "green",+ "name": "Reyna Clay",+ "gender": "female",+ "company": "KINETICA",+ "email": "reynaclay@kinetica.com",+ "phone": "+1 (865) 425-3747",+ "address": "480 Dakota Place, Kimmell, Utah, 6677",+ "about": "Tempor esse ex amet aliqua incididunt incididunt qui commodo laborum incididunt deserunt elit id consequat. Proident duis ut ullamco non ea magna fugiat fugiat Lorem minim. Incididunt tempor nostrud proident irure laboris consectetur elit labore adipisicing fugiat nulla quis ipsum consequat. Tempor mollit pariatur irure in nisi minim magna excepteur. Aliquip et laborum cillum adipisicing consequat.\r\n",+ "registered": "2014-10-30T08:53:04 +07:00",+ "latitude": 38.437675,+ "longitude": 42.847793,+ "tags": [+ "incididunt",+ "est",+ "mollit",+ "nulla",+ "ipsum",+ "ea",+ "ea"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Glenna Macdonald"+ },+ {+ "id": 1,+ "name": "Bertha Meadows"+ },+ {+ "id": 2,+ "name": "Oneill Barnes"+ }+ ],+ "greeting": "Hello, Reyna Clay! You have 6 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a900238319b9b407aa0",+ "index": 32,+ "guid": "fa5c52e1-9a9d-44d4-8e6b-5a65221ab142",+ "isActive": true,+ "balance": "$3,113.15",+ "picture": "http://placehold.it/32x32",+ "age": 24,+ "eyeColor": "blue",+ "name": "Felicia Harris",+ "gender": "female",+ "company": "FITCORE",+ "email": "feliciaharris@fitcore.com",+ "phone": "+1 (814) 449-2730",+ "address": "641 Hazel Court, Bawcomville, Wisconsin, 4111",+ "about": "Magna in elit aute ipsum anim dolore et exercitation sunt occaecat velit. Sint tempor nulla sit laborum dolor ex irure nisi nulla veniam in labore laborum. Nulla magna excepteur exercitation aute occaecat consequat laborum Lorem velit occaecat aliqua qui. Id in aliqua dolore fugiat duis elit laborum commodo cillum ex aute minim eu.\r\n",+ "registered": "2014-04-15T21:31:39 +07:00",+ "latitude": -58.891583,+ "longitude": -162.554134,+ "tags": [+ "eiusmod",+ "dolor",+ "enim",+ "cupidatat",+ "labore",+ "sunt",+ "consectetur"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Rich Lott"+ },+ {+ "id": 1,+ "name": "Rebecca Cardenas"+ },+ {+ "id": 2,+ "name": "Jarvis Barron"+ }+ ],+ "greeting": "Hello, Felicia Harris! You have 7 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90f03941c94fe50d08",+ "index": 33,+ "guid": "49070cf3-b2f3-445e-86ec-3ae9cddc474d",+ "isActive": false,+ "balance": "$1,105.05",+ "picture": "http://placehold.it/32x32",+ "age": 35,+ "eyeColor": "green",+ "name": "Josefina Holland",+ "gender": "female",+ "company": "GOGOL",+ "email": "josefinaholland@gogol.com",+ "phone": "+1 (809) 411-2991",+ "address": "778 McKibben Street, Whitehaven, Louisiana, 2079",+ "about": "Cillum ipsum cupidatat et dolor minim aliqua. Laborum culpa magna ullamco nulla ut labore deserunt amet sunt est esse do. Consequat aliquip eiusmod ipsum tempor. Voluptate exercitation nisi nulla dolor esse ullamco occaecat. Sint minim reprehenderit anim tempor deserunt sit exercitation. Qui proident cillum eu voluptate adipisicing velit tempor sunt sunt ipsum. Enim anim ea ea eu excepteur excepteur laboris eu.\r\n",+ "registered": "2014-09-13T12:46:51 +07:00",+ "latitude": 81.172596,+ "longitude": -151.851605,+ "tags": [+ "velit",+ "ad",+ "tempor",+ "tempor",+ "adipisicing",+ "nulla",+ "minim"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Lester Woods"+ },+ {+ "id": 1,+ "name": "Audra Shepherd"+ },+ {+ "id": 2,+ "name": "Chandler Church"+ }+ ],+ "greeting": "Hello, Josefina Holland! You have 5 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a9008a3955509cf065f",+ "index": 34,+ "guid": "4c838bee-e8b1-4c22-b8ad-e0e5d0822334",+ "isActive": false,+ "balance": "$3,032.13",+ "picture": "http://placehold.it/32x32",+ "age": 32,+ "eyeColor": "green",+ "name": "Susie Cash",+ "gender": "female",+ "company": "DOGSPA",+ "email": "susiecash@dogspa.com",+ "phone": "+1 (991) 447-2298",+ "address": "361 Quincy Street, Duryea, Florida, 7538",+ "about": "Officia eu non proident ad ea quis eu ea amet irure aliqua qui. Ea in laborum do sit. Dolor proident voluptate excepteur sit. Tempor nulla anim ex proident ipsum laboris laboris cupidatat esse dolore ex fugiat proident. Excepteur exercitation pariatur ex velit. In adipisicing eu eiusmod elit dolore ullamco nulla sit ut ut anim aliquip. Et eu eu aliquip ex aute aliquip veniam sint pariatur non incididunt in aliqua sit.\r\n",+ "registered": "2014-09-14T22:55:19 +07:00",+ "latitude": 8.46119,+ "longitude": -1.171475,+ "tags": [+ "voluptate",+ "irure",+ "ex",+ "proident",+ "nulla",+ "in",+ "esse"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Cassie Whitley"+ },+ {+ "id": 1,+ "name": "Shawna Todd"+ },+ {+ "id": 2,+ "name": "Antoinette Brooks"+ }+ ],+ "greeting": "Hello, Susie Cash! You have 1 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a9079c5bce30e9c0a68",+ "index": 35,+ "guid": "7a70e0df-c23b-435d-8d19-864cc1bd09e6",+ "isActive": false,+ "balance": "$2,523.44",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "brown",+ "name": "Marquez Hartman",+ "gender": "male",+ "company": "BUZZMAKER",+ "email": "marquezhartman@buzzmaker.com",+ "phone": "+1 (880) 574-2420",+ "address": "326 Church Avenue, Yardville, Indiana, 6743",+ "about": "Ullamco reprehenderit pariatur veniam enim est nulla laboris ullamco eiusmod eu Lorem amet in amet. Incididunt consectetur reprehenderit tempor Lorem aute eiusmod laborum sunt mollit excepteur qui ea enim. Consectetur enim excepteur proident incididunt adipisicing duis est amet quis proident laboris. Consectetur Lorem consequat incididunt eiusmod mollit id amet velit quis ipsum labore. Cupidatat id minim cillum qui consequat quis non quis irure dolor voluptate ea eu.\r\n",+ "registered": "2014-06-16T07:23:30 +07:00",+ "latitude": -88.970617,+ "longitude": -28.068887,+ "tags": [+ "nostrud",+ "adipisicing",+ "quis",+ "voluptate",+ "dolore",+ "dolore",+ "reprehenderit"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Florence David"+ },+ {+ "id": 1,+ "name": "Lynn Mcleod"+ },+ {+ "id": 2,+ "name": "Catherine Abbott"+ }+ ],+ "greeting": "Hello, Marquez Hartman! You have 10 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a902bf5baf83c4fafcd",+ "index": 36,+ "guid": "56ac4022-1ed3-4298-9b70-c6060c69b13c",+ "isActive": false,+ "balance": "$1,162.32",+ "picture": "http://placehold.it/32x32",+ "age": 35,+ "eyeColor": "green",+ "name": "Bishop Gibbs",+ "gender": "male",+ "company": "MICROLUXE",+ "email": "bishopgibbs@microluxe.com",+ "phone": "+1 (808) 584-2587",+ "address": "801 Exeter Street, Trucksville, New Hampshire, 4871",+ "about": "Incididunt sit eu sunt cupidatat aute do eu eu culpa. Laborum adipisicing sit anim sit dolor labore commodo minim proident ullamco laboris sit irure. Duis dolore cupidatat ullamco anim reprehenderit aliquip incididunt sunt eu id non proident non.\r\n",+ "registered": "2014-09-10T02:39:14 +07:00",+ "latitude": -3.268064,+ "longitude": 149.311591,+ "tags": [+ "enim",+ "aute",+ "commodo",+ "consectetur",+ "Lorem",+ "est",+ "cillum"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Head Pickett"+ },+ {+ "id": 1,+ "name": "Thornton Russo"+ },+ {+ "id": 2,+ "name": "Hooper Rivera"+ }+ ],+ "greeting": "Hello, Bishop Gibbs! You have 9 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90a4406555b5bdab8f",+ "index": 37,+ "guid": "0f052dd2-283e-441e-86d7-b7f7b47224f1",+ "isActive": true,+ "balance": "$3,306.81",+ "picture": "http://placehold.it/32x32",+ "age": 34,+ "eyeColor": "brown",+ "name": "Carr Strickland",+ "gender": "male",+ "company": "EXERTA",+ "email": "carrstrickland@exerta.com",+ "phone": "+1 (862) 455-3845",+ "address": "730 Aberdeen Street, Klondike, Kansas, 4412",+ "about": "Pariatur velit qui Lorem cillum labore veniam minim. Nisi reprehenderit commodo consectetur commodo velit. Ipsum dolor ea mollit excepteur minim do excepteur. Aliquip cillum quis nostrud cillum duis eu laborum reprehenderit adipisicing adipisicing do exercitation. Laborum Lorem sunt voluptate qui quis officia nisi et elit sint veniam. Lorem velit ad do amet labore veniam consectetur.\r\n",+ "registered": "2014-01-19T10:53:58 +08:00",+ "latitude": -45.243563,+ "longitude": -17.8448,+ "tags": [+ "mollit",+ "ex",+ "qui",+ "fugiat",+ "consequat",+ "consectetur",+ "do"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Rosario Gomez"+ },+ {+ "id": 1,+ "name": "Robinson Robinson"+ },+ {+ "id": 2,+ "name": "Vicki Moreno"+ }+ ],+ "greeting": "Hello, Carr Strickland! You have 2 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a9097f6a585321fe001",+ "index": 38,+ "guid": "eee159c2-73ac-44b7-9054-d72295d3178a",+ "isActive": true,+ "balance": "$3,336.97",+ "picture": "http://placehold.it/32x32",+ "age": 30,+ "eyeColor": "brown",+ "name": "Stephens Harper",+ "gender": "male",+ "company": "KIDSTOCK",+ "email": "stephensharper@kidstock.com",+ "phone": "+1 (989) 464-3887",+ "address": "315 Hewes Street, Cuylerville, Pennsylvania, 7331",+ "about": "Et ea Lorem labore consequat laboris. Aliqua irure elit aliqua ad fugiat. Commodo cupidatat incididunt ut nostrud consequat elit ad esse magna nisi nostrud dolore eu. Minim incididunt esse ullamco esse ullamco deserunt reprehenderit commodo ut. Quis sint cupidatat excepteur et laboris incididunt id esse irure nostrud sint nostrud ut pariatur. Pariatur officia aute ullamco laboris nisi elit quis labore Lorem minim ad. Ea esse anim commodo fugiat exercitation voluptate eiusmod aliquip amet enim nulla mollit excepteur nisi.\r\n",+ "registered": "2014-03-02T06:45:25 +08:00",+ "latitude": -88.39292,+ "longitude": -121.170605,+ "tags": [+ "ullamco",+ "est",+ "mollit",+ "id",+ "commodo",+ "Lorem",+ "nostrud"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Castaneda Dillon"+ },+ {+ "id": 1,+ "name": "Morin Hodge"+ },+ {+ "id": 2,+ "name": "Vincent Lamb"+ }+ ],+ "greeting": "Hello, Stephens Harper! You have 2 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90357d07212fdefd7a",+ "index": 39,+ "guid": "160a80a4-8e5d-483a-93ed-0a37ee359f04",+ "isActive": true,+ "balance": "$1,588.64",+ "picture": "http://placehold.it/32x32",+ "age": 32,+ "eyeColor": "green",+ "name": "Espinoza May",+ "gender": "male",+ "company": "ZIDOX",+ "email": "espinozamay@zidox.com",+ "phone": "+1 (955) 420-2244",+ "address": "614 Alice Court, Vienna, Delaware, 5018",+ "about": "Pariatur voluptate culpa enim enim sunt dolor laborum consequat officia est nostrud. Ad pariatur labore reprehenderit cillum dolor consequat quis eu fugiat. Ut fugiat do dolor minim voluptate incididunt laboris magna deserunt. Culpa incididunt fugiat nostrud qui incididunt velit laboris deserunt exercitation velit.\r\n",+ "registered": "2014-09-16T06:10:45 +07:00",+ "latitude": -28.413217,+ "longitude": -76.45198,+ "tags": [+ "ullamco",+ "ut",+ "nulla",+ "consequat",+ "ea",+ "in",+ "commodo"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Virginia Obrien"+ },+ {+ "id": 1,+ "name": "Snider Hopper"+ },+ {+ "id": 2,+ "name": "Fannie Harrell"+ }+ ],+ "greeting": "Hello, Espinoza May! You have 3 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a901e753e41d1232a42",+ "index": 40,+ "guid": "7f3923e7-2fad-4210-b051-bd805e505d06",+ "isActive": false,+ "balance": "$2,512.14",+ "picture": "http://placehold.it/32x32",+ "age": 28,+ "eyeColor": "green",+ "name": "Morrison Guerrero",+ "gender": "male",+ "company": "MARQET",+ "email": "morrisonguerrero@marqet.com",+ "phone": "+1 (881) 456-3335",+ "address": "157 Huntington Street, Topaz, Georgia, 6068",+ "about": "Velit cupidatat eiusmod elit ut adipisicing. Proident pariatur consequat ullamco velit dolore do esse adipisicing non est ea. Velit non amet nisi aliqua est veniam dolor. Cillum id labore qui ut aute pariatur exercitation ut incididunt velit aute.\r\n",+ "registered": "2014-11-12T21:01:15 +08:00",+ "latitude": -43.420946,+ "longitude": 23.215515,+ "tags": [+ "sit",+ "dolore",+ "aliqua",+ "esse",+ "et",+ "cillum",+ "mollit"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Pamela Stanton"+ },+ {+ "id": 1,+ "name": "Spence Banks"+ },+ {+ "id": 2,+ "name": "Newton Cooley"+ }+ ],+ "greeting": "Hello, Morrison Guerrero! You have 4 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a9098c06d55fa03398f",+ "index": 41,+ "guid": "c17e4f56-ca2b-48fd-bbc4-aea053062ebd",+ "isActive": false,+ "balance": "$3,405.25",+ "picture": "http://placehold.it/32x32",+ "age": 26,+ "eyeColor": "brown",+ "name": "Janna Porter",+ "gender": "female",+ "company": "NIMON",+ "email": "jannaporter@nimon.com",+ "phone": "+1 (974) 475-2497",+ "address": "231 Wythe Place, Stonybrook, Alaska, 6291",+ "about": "Veniam aute dolor Lorem dolore enim eiusmod veniam esse pariatur duis nisi. Eu sit sunt in exercitation amet veniam reprehenderit voluptate proident officia. Dolore aliquip laboris veniam cupidatat non cupidatat ipsum esse labore Lorem reprehenderit ex. Amet magna do officia proident laborum laboris enim. Ea sunt quis officia minim ea in id cillum. Aute ipsum aliquip fugiat tempor proident sit pariatur duis fugiat fugiat esse cillum eiusmod laboris.\r\n",+ "registered": "2014-08-21T22:08:24 +07:00",+ "latitude": -43.52587,+ "longitude": 143.40506,+ "tags": [+ "ipsum",+ "consequat",+ "labore",+ "tempor",+ "ipsum",+ "exercitation",+ "sint"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Bray Francis"+ },+ {+ "id": 1,+ "name": "Whitley Guthrie"+ },+ {+ "id": 2,+ "name": "Christa Short"+ }+ ],+ "greeting": "Hello, Janna Porter! You have 1 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90ddf3f9e967357339",+ "index": 42,+ "guid": "5b194b7d-c5ca-4cdd-9239-6aa6f9b28e2f",+ "isActive": false,+ "balance": "$1,601.96",+ "picture": "http://placehold.it/32x32",+ "age": 31,+ "eyeColor": "green",+ "name": "Sandoval Melton",+ "gender": "male",+ "company": "GENMEX",+ "email": "sandovalmelton@genmex.com",+ "phone": "+1 (826) 536-3504",+ "address": "726 Lester Court, Gracey, Colorado, 4092",+ "about": "Fugiat pariatur elit Lorem amet fugiat tempor. Quis sint fugiat officia deserunt voluptate fugiat aliquip reprehenderit est laborum. Ut id ullamco Lorem esse occaecat eu officia veniam velit. Aliquip nisi voluptate id aliquip qui tempor commodo occaecat velit adipisicing nisi cillum id adipisicing.\r\n",+ "registered": "2014-09-05T08:54:55 +07:00",+ "latitude": -66.159672,+ "longitude": -135.605108,+ "tags": [+ "deserunt",+ "minim",+ "nulla",+ "ea",+ "tempor",+ "reprehenderit",+ "nulla"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Veronica Goodwin"+ },+ {+ "id": 1,+ "name": "Heather Pena"+ },+ {+ "id": 2,+ "name": "Lynch Crane"+ }+ ],+ "greeting": "Hello, Sandoval Melton! You have 2 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a904d114bb57f0826af",+ "index": 43,+ "guid": "57e4715d-f7e7-4843-9844-638648315628",+ "isActive": false,+ "balance": "$1,820.21",+ "picture": "http://placehold.it/32x32",+ "age": 34,+ "eyeColor": "blue",+ "name": "Flynn Fitzgerald",+ "gender": "male",+ "company": "ORBEAN",+ "email": "flynnfitzgerald@orbean.com",+ "phone": "+1 (931) 578-2443",+ "address": "662 Degraw Street, Morgandale, Alabama, 5945",+ "about": "Nulla anim qui duis ea do consectetur eiusmod commodo. Minim sunt aliqua velit ullamco velit dolor in amet. Eiusmod Lorem sint ea ea nisi ullamco ut officia magna id adipisicing. Ut eu minim pariatur incididunt non nisi in nostrud culpa magna anim. Veniam dolor consequat cillum sunt elit.\r\n",+ "registered": "2014-06-21T08:11:23 +07:00",+ "latitude": 17.108863,+ "longitude": -21.608292,+ "tags": [+ "officia",+ "quis",+ "sint",+ "ipsum",+ "esse",+ "commodo",+ "aute"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Browning Mcdonald"+ },+ {+ "id": 1,+ "name": "Austin Lane"+ },+ {+ "id": 2,+ "name": "Blankenship Ferrell"+ }+ ],+ "greeting": "Hello, Flynn Fitzgerald! You have 6 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a903a4a0629f547f5ab",+ "index": 44,+ "guid": "1e128e33-65bf-4420-ae93-f228d030401c",+ "isActive": false,+ "balance": "$3,158.96",+ "picture": "http://placehold.it/32x32",+ "age": 25,+ "eyeColor": "brown",+ "name": "Holden Golden",+ "gender": "male",+ "company": "QABOOS",+ "email": "holdengolden@qaboos.com",+ "phone": "+1 (825) 535-2422",+ "address": "892 Vandervoort Place, Hessville, Guam, 3942",+ "about": "Non sunt cupidatat ipsum nostrud qui ad ex nostrud fugiat laboris minim. Aliquip dolore est proident aliquip in non culpa. Minim ut laboris duis proident commodo occaecat duis duis cupidatat incididunt aliqua. Ad qui anim non occaecat excepteur labore consequat Lorem.\r\n",+ "registered": "2014-09-11T00:33:16 +07:00",+ "latitude": -3.274271,+ "longitude": -151.539207,+ "tags": [+ "nostrud",+ "non",+ "sint",+ "laborum",+ "deserunt",+ "velit",+ "sit"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Barbara Sharpe"+ },+ {+ "id": 1,+ "name": "Jerri Martinez"+ },+ {+ "id": 2,+ "name": "Ronda Montoya"+ }+ ],+ "greeting": "Hello, Holden Golden! You have 3 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a9079e20c148518a60a",+ "index": 45,+ "guid": "90fa284f-6cba-42d4-8484-6edb1ffc260b",+ "isActive": false,+ "balance": "$1,739.35",+ "picture": "http://placehold.it/32x32",+ "age": 27,+ "eyeColor": "blue",+ "name": "Maxwell Hodges",+ "gender": "male",+ "company": "DOGTOWN",+ "email": "maxwellhodges@dogtown.com",+ "phone": "+1 (962) 527-3585",+ "address": "696 Baughman Place, Cucumber, South Carolina, 5454",+ "about": "Officia ea in non veniam ipsum ea magna enim velit. Enim mollit duis consectetur magna fugiat nostrud cillum duis. Voluptate qui nostrud amet ea eiusmod consectetur cupidatat fugiat in eiusmod amet esse excepteur aute. Magna qui duis ex qui irure esse amet. Quis amet ex esse aliquip mollit. Deserunt consectetur eiusmod culpa reprehenderit. Duis quis excepteur non in consectetur commodo.\r\n",+ "registered": "2014-03-20T11:37:19 +07:00",+ "latitude": 19.760315,+ "longitude": -26.731699,+ "tags": [+ "magna",+ "aute",+ "consectetur",+ "labore",+ "sunt",+ "pariatur",+ "excepteur"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Violet Vincent"+ },+ {+ "id": 1,+ "name": "West Dorsey"+ },+ {+ "id": 2,+ "name": "Concepcion Hull"+ }+ ],+ "greeting": "Hello, Maxwell Hodges! You have 3 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a903c504d648884f367",+ "index": 46,+ "guid": "7fd30275-a097-41e0-8924-252f0a14d6ba",+ "isActive": false,+ "balance": "$1,153.05",+ "picture": "http://placehold.it/32x32",+ "age": 22,+ "eyeColor": "brown",+ "name": "Chasity Day",+ "gender": "female",+ "company": "EQUITAX",+ "email": "chasityday@equitax.com",+ "phone": "+1 (900) 484-3047",+ "address": "858 Gelston Avenue, Succasunna, Arkansas, 3818",+ "about": "Est ullamco deserunt cillum enim velit velit magna qui nisi eiusmod enim officia sit voluptate. Laboris laborum elit nostrud sit in elit labore occaecat mollit Lorem. Aliquip ipsum dolore cupidatat ad anim sint non. Commodo ut fugiat ut dolor irure id velit enim in Lorem.\r\n",+ "registered": "2014-01-05T08:26:01 +08:00",+ "latitude": -34.705083,+ "longitude": -77.213981,+ "tags": [+ "consectetur",+ "velit",+ "enim",+ "excepteur",+ "ipsum",+ "non",+ "adipisicing"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Judy Trevino"+ },+ {+ "id": 1,+ "name": "Rosie Cervantes"+ },+ {+ "id": 2,+ "name": "Stella Cortez"+ }+ ],+ "greeting": "Hello, Chasity Day! You have 1 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90ac6406c3b9606052",+ "index": 47,+ "guid": "9bcd39b8-10db-40cc-a9f0-73e8179f181b",+ "isActive": true,+ "balance": "$1,755.70",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "green",+ "name": "Richards Mcfadden",+ "gender": "male",+ "company": "ZILLACOM",+ "email": "richardsmcfadden@zillacom.com",+ "phone": "+1 (883) 447-2941",+ "address": "241 Turnbull Avenue, Chesterfield, Ohio, 7594",+ "about": "Fugiat ut qui qui et Lorem ipsum do anim veniam. Sunt ex Lorem et nostrud consectetur esse nostrud qui minim ut veniam commodo. Cillum enim laboris aliquip sunt quis ut et adipisicing deserunt. Est aute amet elit non duis deserunt nisi quis excepteur do velit. Nostrud laboris ullamco sunt occaecat Lorem nostrud laboris.\r\n",+ "registered": "2014-07-04T03:08:44 +07:00",+ "latitude": -66.813737,+ "longitude": 75.337073,+ "tags": [+ "elit",+ "consequat",+ "excepteur",+ "qui",+ "deserunt",+ "sint",+ "ipsum"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Mercado Quinn"+ },+ {+ "id": 1,+ "name": "Lucia Roberts"+ },+ {+ "id": 2,+ "name": "Essie Cohen"+ }+ ],+ "greeting": "Hello, Richards Mcfadden! You have 5 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a9033409e09e42cf3f1",+ "index": 48,+ "guid": "6ea51613-14f0-42b7-97c6-eb7a5cc32226",+ "isActive": true,+ "balance": "$3,907.64",+ "picture": "http://placehold.it/32x32",+ "age": 31,+ "eyeColor": "blue",+ "name": "Sargent Harrington",+ "gender": "male",+ "company": "DIGINETIC",+ "email": "sargentharrington@diginetic.com",+ "phone": "+1 (974) 427-2742",+ "address": "883 Kermit Place, Rehrersburg, Virgin Islands, 4044",+ "about": "Officia eiusmod do ut ipsum voluptate aute mollit minim ea incididunt ipsum commodo. Qui aute commodo dolor id pariatur ullamco adipisicing duis irure reprehenderit aliquip ullamco consequat. Sunt ad non deserunt velit consectetur ipsum. Sit voluptate aliquip nisi ea pariatur proident ut eu cillum. Irure sunt ad aliqua et enim. Deserunt deserunt incididunt Lorem commodo aliqua.\r\n",+ "registered": "2014-06-16T00:32:02 +07:00",+ "latitude": -88.301682,+ "longitude": -16.268399,+ "tags": [+ "Lorem",+ "reprehenderit",+ "consequat",+ "officia",+ "velit",+ "ad",+ "ex"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Dolly Swanson"+ },+ {+ "id": 1,+ "name": "Jeannette Underwood"+ },+ {+ "id": 2,+ "name": "Ayers Wheeler"+ }+ ],+ "greeting": "Hello, Sargent Harrington! You have 3 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a9083fe43074bb5b9c8",+ "index": 49,+ "guid": "d5835fea-0882-4e20-b86e-6dd8b9534b49",+ "isActive": false,+ "balance": "$2,481.41",+ "picture": "http://placehold.it/32x32",+ "age": 22,+ "eyeColor": "green",+ "name": "Kristin Perez",+ "gender": "female",+ "company": "JAMNATION",+ "email": "kristinperez@jamnation.com",+ "phone": "+1 (917) 575-2693",+ "address": "737 Schroeders Avenue, Chemung, Nebraska, 8601",+ "about": "Voluptate id id mollit in aliquip aliquip duis cupidatat elit voluptate proident sit sunt voluptate. Irure ipsum esse duis culpa esse et do officia consequat velit commodo Lorem. Dolore incididunt proident proident officia aliqua mollit nisi exercitation consectetur. Est dolore consectetur aliqua occaecat est. Labore nostrud ipsum aliquip labore elit aliquip magna ex esse do consequat minim id. Sit sint ea ad irure voluptate occaecat duis magna. Sint ex minim irure anim sint do cillum.\r\n",+ "registered": "2014-08-12T23:35:39 +07:00",+ "latitude": 75.002428,+ "longitude": 12.266159,+ "tags": [+ "anim",+ "exercitation",+ "excepteur",+ "amet",+ "aute",+ "mollit",+ "aliquip"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Gilliam Steele"+ },+ {+ "id": 1,+ "name": "Loretta Brennan"+ },+ {+ "id": 2,+ "name": "Ratliff Norton"+ }+ ],+ "greeting": "Hello, Kristin Perez! You have 9 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90f594e03626363339",+ "index": 50,+ "guid": "bdb8284c-7b55-4791-90c0-d9e4abecd91f",+ "isActive": true,+ "balance": "$1,906.85",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "green",+ "name": "Petra Scott",+ "gender": "female",+ "company": "BRAINCLIP",+ "email": "petrascott@brainclip.com",+ "phone": "+1 (942) 449-2471",+ "address": "759 Coleridge Street, Tuskahoma, Virginia, 9943",+ "about": "Consectetur magna consequat ea est. Minim veniam culpa deserunt aliqua in dolor ex aliqua occaecat reprehenderit. Proident in mollit ad est excepteur anim quis aliquip non consequat minim cillum deserunt. Occaecat sint ad et irure sit ad ad sit sint quis sunt nisi.\r\n",+ "registered": "2014-11-12T20:54:05 +08:00",+ "latitude": -64.192199,+ "longitude": -144.535209,+ "tags": [+ "cillum",+ "id",+ "aliqua",+ "reprehenderit",+ "officia",+ "aliquip",+ "in"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Holmes Rasmussen"+ },+ {+ "id": 1,+ "name": "Leach Hickman"+ },+ {+ "id": 2,+ "name": "Noelle Battle"+ }+ ],+ "greeting": "Hello, Petra Scott! You have 9 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a902f79c4cdada83391",+ "index": 51,+ "guid": "c79aaabd-212b-4dc8-b1b5-de14362b550c",+ "isActive": true,+ "balance": "$2,845.25",+ "picture": "http://placehold.it/32x32",+ "age": 32,+ "eyeColor": "brown",+ "name": "Kelli Gates",+ "gender": "female",+ "company": "MUSANPOLY",+ "email": "kelligates@musanpoly.com",+ "phone": "+1 (899) 414-3276",+ "address": "888 Elm Place, Grayhawk, Wyoming, 8032",+ "about": "Nisi excepteur laboris duis magna dolore occaecat dolor cupidatat. Ut commodo proident incididunt ea anim enim deserunt laboris occaecat anim cillum. In amet exercitation officia mollit officia quis exercitation aliqua culpa ullamco consequat excepteur aute mollit. Aliqua tempor consequat ullamco consequat qui duis tempor ex est aliqua id nulla Lorem occaecat. Et laborum culpa pariatur et ad minim. Nulla ad eiusmod pariatur velit aliquip magna duis duis tempor. Nisi ea reprehenderit aliquip magna esse occaecat consectetur ullamco esse.\r\n",+ "registered": "2014-03-01T15:11:58 +08:00",+ "latitude": 30.679655,+ "longitude": -175.200369,+ "tags": [+ "laborum",+ "non",+ "pariatur",+ "ea",+ "non",+ "proident",+ "culpa"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Coleman Mejia"+ },+ {+ "id": 1,+ "name": "Meyers Sellers"+ },+ {+ "id": 2,+ "name": "Stuart Carney"+ }+ ],+ "greeting": "Hello, Kelli Gates! You have 1 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a9040ef999266e0142c",+ "index": 52,+ "guid": "cb9bc903-5e95-4918-91ed-8485d75489fa",+ "isActive": true,+ "balance": "$1,352.24",+ "picture": "http://placehold.it/32x32",+ "age": 29,+ "eyeColor": "green",+ "name": "Maricela Conrad",+ "gender": "female",+ "company": "QUIZKA",+ "email": "maricelaconrad@quizka.com",+ "phone": "+1 (924) 592-2199",+ "address": "339 Virginia Place, Lutsen, Marshall Islands, 1479",+ "about": "Quis commodo cupidatat mollit et deserunt id ut anim nostrud nisi mollit esse commodo laborum. Cillum exercitation anim cillum esse quis consequat. Dolor laboris exercitation irure ullamco excepteur ipsum deserunt. Anim veniam dolore labore exercitation et consectetur eiusmod eu. Aliquip velit consectetur nostrud dolore.\r\n",+ "registered": "2014-06-15T22:10:22 +07:00",+ "latitude": -0.554318,+ "longitude": -65.103334,+ "tags": [+ "adipisicing",+ "irure",+ "deserunt",+ "culpa",+ "cupidatat",+ "do",+ "occaecat"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Gentry Holden"+ },+ {+ "id": 1,+ "name": "Dillard Herrera"+ },+ {+ "id": 2,+ "name": "Guzman Patton"+ }+ ],+ "greeting": "Hello, Maricela Conrad! You have 1 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a905369b0bb27f85607",+ "index": 53,+ "guid": "fa3a125f-2d10-4015-a0fd-68d7e2401a31",+ "isActive": false,+ "balance": "$2,858.28",+ "picture": "http://placehold.it/32x32",+ "age": 34,+ "eyeColor": "green",+ "name": "Simpson Cleveland",+ "gender": "male",+ "company": "ZAPPIX",+ "email": "simpsoncleveland@zappix.com",+ "phone": "+1 (808) 572-3724",+ "address": "202 Georgia Avenue, Jamestown, Texas, 6347",+ "about": "Reprehenderit elit in duis sunt quis consequat mollit ut consequat amet. Incididunt non sint culpa non mollit incididunt elit irure sint excepteur esse sit ut fugiat. Ullamco esse culpa excepteur magna laborum sunt magna ut reprehenderit aute laboris ullamco Lorem ea. Culpa ut sit amet dolor adipisicing veniam non occaecat ex ad ea. Quis nostrud sit mollit aliqua adipisicing.\r\n",+ "registered": "2014-10-27T07:51:50 +07:00",+ "latitude": -34.024135,+ "longitude": 66.799767,+ "tags": [+ "anim",+ "pariatur",+ "fugiat",+ "reprehenderit",+ "ullamco",+ "labore",+ "fugiat"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Hester Howell"+ },+ {+ "id": 1,+ "name": "Deena King"+ },+ {+ "id": 2,+ "name": "Wilkerson Fox"+ }+ ],+ "greeting": "Hello, Simpson Cleveland! You have 10 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a900271aa8695bc5cdf",+ "index": 54,+ "guid": "501e7876-6b3f-4f2e-bbaf-914e6ff23845",+ "isActive": false,+ "balance": "$2,015.78",+ "picture": "http://placehold.it/32x32",+ "age": 23,+ "eyeColor": "brown",+ "name": "Queen Mckay",+ "gender": "female",+ "company": "PROXSOFT",+ "email": "queenmckay@proxsoft.com",+ "phone": "+1 (954) 439-2402",+ "address": "749 Wakeman Place, Sidman, Massachusetts, 3345",+ "about": "Culpa irure velit cupidatat voluptate ad non anim sit sunt in esse adipisicing. Officia amet Lorem et id eiusmod non commodo deserunt irure tempor aute fugiat est cupidatat. Ut amet ad consequat nulla in in deserunt minim ipsum adipisicing eu adipisicing nisi nulla. Qui culpa sunt aute amet est consequat excepteur occaecat voluptate in do. In labore aute sit duis enim sunt qui ullamco est tempor labore aute aliquip. Sunt eu veniam in amet cillum nisi tempor quis in fugiat culpa exercitation sunt. Exercitation enim dolore sit exercitation in mollit culpa magna amet et amet.\r\n",+ "registered": "2014-05-02T07:58:52 +07:00",+ "latitude": -24.836277,+ "longitude": -108.207588,+ "tags": [+ "aliquip",+ "dolor",+ "velit",+ "non",+ "sint",+ "deserunt",+ "ut"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Maynard Shannon"+ },+ {+ "id": 1,+ "name": "Ernestine Sullivan"+ },+ {+ "id": 2,+ "name": "Sullivan Juarez"+ }+ ],+ "greeting": "Hello, Queen Mckay! You have 8 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a902c9d0c4f7379c125",+ "index": 55,+ "guid": "c13147c1-9aab-432b-9eaa-eda127454f06",+ "isActive": false,+ "balance": "$1,498.79",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "green",+ "name": "Madeline Rhodes",+ "gender": "female",+ "company": "LOCAZONE",+ "email": "madelinerhodes@locazone.com",+ "phone": "+1 (817) 404-2650",+ "address": "648 Rochester Avenue, Tetherow, Arizona, 751",+ "about": "Sit velit ea enim mollit ad fugiat anim commodo minim qui sit dolor aliqua. Amet nostrud aliquip qui velit et ea reprehenderit sint ipsum quis. Ut amet aute enim proident. Et officia nostrud voluptate non tempor quis aliquip ullamco commodo consequat fugiat ut. Eiusmod sit excepteur non nostrud esse consequat nulla sunt deserunt aliqua. Commodo laborum voluptate ea eu non excepteur pariatur.\r\n",+ "registered": "2014-03-14T19:50:42 +07:00",+ "latitude": -31.489199,+ "longitude": 124.798218,+ "tags": [+ "tempor",+ "culpa",+ "pariatur",+ "irure",+ "nisi",+ "proident",+ "quis"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Hebert Kline"+ },+ {+ "id": 1,+ "name": "Daisy Cochran"+ },+ {+ "id": 2,+ "name": "Russell Gilmore"+ }+ ],+ "greeting": "Hello, Madeline Rhodes! You have 10 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90b6d8621dab6c9126",+ "index": 56,+ "guid": "2ebcecc1-180e-46b7-bdca-9d9a6babc687",+ "isActive": false,+ "balance": "$3,190.82",+ "picture": "http://placehold.it/32x32",+ "age": 27,+ "eyeColor": "blue",+ "name": "Rasmussen Knapp",+ "gender": "male",+ "company": "BIOSPAN",+ "email": "rasmussenknapp@biospan.com",+ "phone": "+1 (860) 461-3219",+ "address": "214 Williams Court, Brady, Oregon, 5174",+ "about": "Tempor ullamco officia laborum irure cillum est culpa tempor pariatur aliqua officia incididunt tempor. Laboris adipisicing nostrud Lorem veniam enim consequat mollit nisi. Minim nulla culpa dolor esse dolore deserunt reprehenderit adipisicing aliquip.\r\n",+ "registered": "2014-08-11T17:15:51 +07:00",+ "latitude": -25.850361,+ "longitude": -36.01581,+ "tags": [+ "enim",+ "laboris",+ "dolore",+ "amet",+ "nisi",+ "in",+ "aliqua"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Letha Peters"+ },+ {+ "id": 1,+ "name": "Lavonne Mccarthy"+ },+ {+ "id": 2,+ "name": "Hensley Kim"+ }+ ],+ "greeting": "Hello, Rasmussen Knapp! You have 5 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a902e4d6731ddf406bf",+ "index": 57,+ "guid": "7a13b0b9-7cc4-477a-944f-a27eb7e74ae6",+ "isActive": false,+ "balance": "$1,711.06",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "brown",+ "name": "Maryellen Russell",+ "gender": "female",+ "company": "MAXEMIA",+ "email": "maryellenrussell@maxemia.com",+ "phone": "+1 (839) 590-2573",+ "address": "514 Roosevelt Court, Sugartown, American Samoa, 6602",+ "about": "Pariatur laborum nostrud aliqua nisi cillum sunt laborum cillum minim pariatur et consectetur minim adipisicing. Exercitation non dolor id voluptate aute sint sunt. Nostrud cupidatat officia dolor cupidatat ex irure non. Fugiat laboris quis id aliqua sunt consectetur est ea. Eiusmod mollit enim Lorem cupidatat consectetur anim nostrud enim eu irure. Et eiusmod velit esse fugiat elit laboris labore voluptate ipsum. Excepteur consequat proident quis voluptate excepteur nulla in.\r\n",+ "registered": "2014-05-17T21:19:21 +07:00",+ "latitude": -15.634102,+ "longitude": -81.860909,+ "tags": [+ "ea",+ "ipsum",+ "esse",+ "veniam",+ "reprehenderit",+ "adipisicing",+ "do"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Virgie Whitaker"+ },+ {+ "id": 1,+ "name": "Earlene Ruiz"+ },+ {+ "id": 2,+ "name": "Rosa Estrada"+ }+ ],+ "greeting": "Hello, Maryellen Russell! You have 5 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a906ea1b53a8de569dd",+ "index": 58,+ "guid": "0e91224f-af4a-4cb0-a51e-5874ad140b32",+ "isActive": false,+ "balance": "$1,226.26",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "blue",+ "name": "Wright Morris",+ "gender": "male",+ "company": "APPLICA",+ "email": "wrightmorris@applica.com",+ "phone": "+1 (968) 550-2677",+ "address": "630 Hornell Loop, Sparkill, Montana, 7355",+ "about": "Veniam commodo nostrud nostrud ullamco do aliquip quis dolore laboris culpa minim do est. In sunt consequat irure veniam minim duis ex commodo duis. Ullamco eu reprehenderit dolore eiusmod est exercitation nisi tempor.\r\n",+ "registered": "2014-02-05T10:33:53 +08:00",+ "latitude": -16.050009,+ "longitude": -149.883606,+ "tags": [+ "Lorem",+ "in",+ "est",+ "consequat",+ "cillum",+ "adipisicing",+ "commodo"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Washington Carson"+ },+ {+ "id": 1,+ "name": "Hines Bean"+ },+ {+ "id": 2,+ "name": "Cox Powell"+ }+ ],+ "greeting": "Hello, Wright Morris! You have 7 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a9047deb3b6b5122221",+ "index": 59,+ "guid": "f85bae2d-b72a-4f81-b596-b5338ec41578",+ "isActive": true,+ "balance": "$1,928.94",+ "picture": "http://placehold.it/32x32",+ "age": 26,+ "eyeColor": "brown",+ "name": "Agnes Guzman",+ "gender": "female",+ "company": "PEARLESSA",+ "email": "agnesguzman@pearlessa.com",+ "phone": "+1 (859) 451-3816",+ "address": "874 Duffield Street, Benson, Hawaii, 1388",+ "about": "Ad voluptate incididunt ullamco ullamco velit adipisicing culpa aute minim adipisicing non. Consectetur elit ullamco mollit ipsum aliqua in enim Lorem eiusmod nisi fugiat exercitation. Do amet pariatur deserunt ex labore exercitation non ad commodo aliquip. Nostrud magna ipsum reprehenderit qui consectetur cillum irure nostrud do quis excepteur cillum.\r\n",+ "registered": "2014-07-28T12:22:31 +07:00",+ "latitude": -89.041016,+ "longitude": -4.513498,+ "tags": [+ "eiusmod",+ "deserunt",+ "deserunt",+ "eiusmod",+ "minim",+ "nisi",+ "magna"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Kari Trujillo"+ },+ {+ "id": 1,+ "name": "Kaye Sloan"+ },+ {+ "id": 2,+ "name": "Aguilar Fields"+ }+ ],+ "greeting": "Hello, Agnes Guzman! You have 9 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a905ad56237e1e3ae99",+ "index": 60,+ "guid": "3244774e-3c8d-4c84-8ae6-d04486ce05d7",+ "isActive": false,+ "balance": "$3,045.23",+ "picture": "http://placehold.it/32x32",+ "age": 27,+ "eyeColor": "green",+ "name": "Jill Evans",+ "gender": "female",+ "company": "GOLISTIC",+ "email": "jillevans@golistic.com",+ "phone": "+1 (871) 577-2459",+ "address": "738 Putnam Avenue, Ona, South Dakota, 4749",+ "about": "Irure exercitation esse quis commodo sunt laborum esse id anim. Ut ut ad quis qui id labore ut tempor labore velit laborum pariatur. Dolore ipsum ea tempor excepteur esse cillum sit non eu sit irure adipisicing mollit. Nulla ut proident velit consequat officia magna ex duis proident aliqua amet exercitation do commodo. Nulla Lorem ad reprehenderit mollit deserunt veniam qui duis enim enim consectetur do.\r\n",+ "registered": "2014-05-05T11:50:14 +07:00",+ "latitude": -56.941561,+ "longitude": -169.158104,+ "tags": [+ "consequat",+ "minim",+ "minim",+ "laborum",+ "aute",+ "nisi",+ "aliqua"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Compton Becker"+ },+ {+ "id": 1,+ "name": "Conner Wall"+ },+ {+ "id": 2,+ "name": "Bright Harvey"+ }+ ],+ "greeting": "Hello, Jill Evans! You have 2 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90f530d8bc9e6faf86",+ "index": 61,+ "guid": "a983ed9d-fb1b-48ee-94b7-54b33634ccbc",+ "isActive": false,+ "balance": "$3,091.12",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "brown",+ "name": "Susana Berry",+ "gender": "female",+ "company": "POWERNET",+ "email": "susanaberry@powernet.com",+ "phone": "+1 (879) 454-3173",+ "address": "141 Cambridge Place, Florence, District Of Columbia, 6760",+ "about": "Magna occaecat laborum voluptate excepteur. Proident esse voluptate enim est exercitation elit voluptate minim ex. Velit officia cupidatat sit quis reprehenderit minim voluptate et nulla cupidatat duis mollit. Aute incididunt id magna nostrud cupidatat qui sit. Enim anim enim excepteur est sunt non enim proident sit non deserunt et veniam culpa. Ullamco irure ullamco id esse exercitation anim et fugiat labore. Do enim exercitation deserunt sint consectetur occaecat commodo commodo elit.\r\n",+ "registered": "2014-06-08T14:24:28 +07:00",+ "latitude": 75.590221,+ "longitude": -127.23641,+ "tags": [+ "esse",+ "anim",+ "est",+ "anim",+ "esse",+ "adipisicing",+ "mollit"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Helene Holcomb"+ },+ {+ "id": 1,+ "name": "Kramer Gregory"+ },+ {+ "id": 2,+ "name": "Fitzgerald Graves"+ }+ ],+ "greeting": "Hello, Susana Berry! You have 1 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90e6f9c07f205357ec",+ "index": 62,+ "guid": "26cecce2-1202-4703-8bf5-8ff431336b37",+ "isActive": false,+ "balance": "$3,437.96",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "blue",+ "name": "Weeks Wallace",+ "gender": "male",+ "company": "SUREMAX",+ "email": "weekswallace@suremax.com",+ "phone": "+1 (946) 528-2733",+ "address": "219 Dekalb Avenue, Hasty, North Carolina, 7278",+ "about": "Magna dolor ex dolor eiusmod sint laboris consequat non magna ipsum. Nostrud qui aute ut consectetur in amet deserunt aliqua voluptate. In velit nisi voluptate amet consequat. Tempor deserunt velit ut aliqua duis cupidatat laboris amet in ipsum aliquip adipisicing. Quis anim cillum labore ipsum commodo deserunt mollit tempor tempor pariatur dolore. Irure aute ipsum do occaecat laborum eiusmod ad proident exercitation elit cillum do.\r\n",+ "registered": "2014-07-17T22:33:55 +07:00",+ "latitude": -22.986103,+ "longitude": -110.848014,+ "tags": [+ "ut",+ "irure",+ "elit",+ "quis",+ "ut",+ "fugiat",+ "sunt"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Colon Tyler"+ },+ {+ "id": 1,+ "name": "Dianne Lucas"+ },+ {+ "id": 2,+ "name": "Mathews Acosta"+ }+ ],+ "greeting": "Hello, Weeks Wallace! You have 8 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a9034039bde61fe5fdb",+ "index": 63,+ "guid": "cad69671-eb0a-4128-8024-9a0f469cf1f8",+ "isActive": true,+ "balance": "$2,503.03",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "green",+ "name": "Watson Tucker",+ "gender": "male",+ "company": "IMKAN",+ "email": "watsontucker@imkan.com",+ "phone": "+1 (841) 499-3837",+ "address": "297 Falmouth Street, Woodlands, Tennessee, 2227",+ "about": "Do aliquip laboris voluptate aliqua duis duis qui. Lorem officia consectetur et in nulla do aliquip occaecat labore officia sunt ipsum ad consequat. Culpa voluptate adipisicing dolore do velit ea.\r\n",+ "registered": "2014-09-16T17:39:32 +07:00",+ "latitude": 76.336221,+ "longitude": -154.036452,+ "tags": [+ "veniam",+ "non",+ "aliquip",+ "ex",+ "esse",+ "sint",+ "voluptate"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Lolita Finch"+ },+ {+ "id": 1,+ "name": "Gilmore Solis"+ },+ {+ "id": 2,+ "name": "Faith Gallegos"+ }+ ],+ "greeting": "Hello, Watson Tucker! You have 9 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90780b195513995278",+ "index": 64,+ "guid": "625810dc-6353-4387-862c-e71ed6115966",+ "isActive": false,+ "balance": "$2,428.28",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "green",+ "name": "Levy Ortega",+ "gender": "male",+ "company": "FIBEROX",+ "email": "levyortega@fiberox.com",+ "phone": "+1 (819) 514-2393",+ "address": "485 Dunne Place, Sena, Idaho, 1583",+ "about": "Exercitation reprehenderit voluptate aliqua laborum dolore consequat pariatur ipsum occaecat culpa et dolore voluptate. Laborum ut adipisicing exercitation irure ipsum ea. Occaecat aute officia et qui id elit adipisicing consectetur. Laborum ullamco pariatur eiusmod dolore aliqua ea nostrud. Occaecat ullamco nostrud deserunt ea officia. Deserunt incididunt et laboris veniam laboris adipisicing culpa laborum occaecat culpa sit labore. Irure in ipsum exercitation ea laboris culpa.\r\n",+ "registered": "2014-06-19T01:29:28 +07:00",+ "latitude": -66.489978,+ "longitude": 35.142253,+ "tags": [+ "consequat",+ "ut",+ "ipsum",+ "ullamco",+ "anim",+ "irure",+ "consectetur"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Nellie Webb"+ },+ {+ "id": 1,+ "name": "Sheri Roy"+ },+ {+ "id": 2,+ "name": "Elizabeth Cooke"+ }+ ],+ "greeting": "Hello, Levy Ortega! You have 3 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a901df67d5f687df4ab",+ "index": 65,+ "guid": "73d49a86-1caa-4ef5-b637-aef68b215e96",+ "isActive": true,+ "balance": "$3,990.52",+ "picture": "http://placehold.it/32x32",+ "age": 24,+ "eyeColor": "blue",+ "name": "Webster Conway",+ "gender": "male",+ "company": "PRISMATIC",+ "email": "websterconway@prismatic.com",+ "phone": "+1 (857) 462-3648",+ "address": "557 Dekoven Court, Sandston, Palau, 8537",+ "about": "Fugiat non velit fugiat sint minim magna occaecat deserunt enim adipisicing excepteur amet. Esse incididunt mollit nisi ut id consectetur qui laborum consequat et occaecat. Tempor cupidatat enim sunt cillum. Laborum consequat Lorem enim fugiat id voluptate incididunt aliquip eu esse dolor duis ad. Officia dolore duis nisi veniam ut ut dolore fugiat deserunt aute consectetur. Excepteur voluptate mollit velit duis ullamco voluptate ullamco.\r\n",+ "registered": "2014-04-30T14:39:28 +07:00",+ "latitude": -67.082095,+ "longitude": 38.979656,+ "tags": [+ "amet",+ "aliquip",+ "ea",+ "culpa",+ "incididunt",+ "dolor",+ "fugiat"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Sharp Ramirez"+ },+ {+ "id": 1,+ "name": "Leona Campbell"+ },+ {+ "id": 2,+ "name": "Hyde Reyes"+ }+ ],+ "greeting": "Hello, Webster Conway! You have 3 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90f7b820f93d4df443",+ "index": 66,+ "guid": "1a306b16-3a38-426c-9254-22dd7264c108",+ "isActive": true,+ "balance": "$2,194.31",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "brown",+ "name": "Hill Lancaster",+ "gender": "male",+ "company": "UNIWORLD",+ "email": "hilllancaster@uniworld.com",+ "phone": "+1 (836) 462-3865",+ "address": "786 Dictum Court, Roulette, Minnesota, 3625",+ "about": "Adipisicing ea commodo et nulla ullamco fugiat do magna occaecat consectetur cupidatat nisi fugiat consequat. Velit veniam eu cupidatat adipisicing culpa non non velit amet labore. Dolore dolor enim eiusmod ipsum excepteur non sint ullamco irure laboris nulla id.\r\n",+ "registered": "2014-03-09T12:51:14 +07:00",+ "latitude": -65.924237,+ "longitude": 161.521943,+ "tags": [+ "amet",+ "id",+ "aliquip",+ "aliquip",+ "exercitation",+ "excepteur",+ "cupidatat"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Morrow Mullen"+ },+ {+ "id": 1,+ "name": "Calderon Campos"+ },+ {+ "id": 2,+ "name": "Janis Ramsey"+ }+ ],+ "greeting": "Hello, Hill Lancaster! You have 10 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a906c7f0305536c965c",+ "index": 67,+ "guid": "d1dadd20-7ced-447d-ba72-61e886f4195e",+ "isActive": true,+ "balance": "$3,014.64",+ "picture": "http://placehold.it/32x32",+ "age": 25,+ "eyeColor": "brown",+ "name": "Fletcher Pearson",+ "gender": "male",+ "company": "QOT",+ "email": "fletcherpearson@qot.com",+ "phone": "+1 (930) 439-2213",+ "address": "779 Middagh Street, Crayne, Illinois, 2229",+ "about": "Nulla sit officia velit dolore eiusmod veniam anim laborum Lorem anim et enim irure. Quis labore ad proident occaecat dolore tempor occaecat dolor dolore aliqua laboris esse enim. Dolore tempor cupidatat aute labore aliqua nulla non est.\r\n",+ "registered": "2014-04-25T09:09:10 +07:00",+ "latitude": -2.329892,+ "longitude": 135.411164,+ "tags": [+ "magna",+ "ipsum",+ "tempor",+ "velit",+ "esse",+ "magna",+ "nisi"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Tonya Ashley"+ },+ {+ "id": 1,+ "name": "Latisha Burris"+ },+ {+ "id": 2,+ "name": "Tracey Rowe"+ }+ ],+ "greeting": "Hello, Fletcher Pearson! You have 9 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a9057e5269ab81d8e18",+ "index": 68,+ "guid": "4723bd56-76cb-4a30-bdf5-8b4c4c9805aa",+ "isActive": false,+ "balance": "$3,114.82",+ "picture": "http://placehold.it/32x32",+ "age": 23,+ "eyeColor": "blue",+ "name": "Odessa Lawson",+ "gender": "female",+ "company": "JOVIOLD",+ "email": "odessalawson@joviold.com",+ "phone": "+1 (921) 400-3177",+ "address": "443 Ryder Avenue, Camino, Missouri, 487",+ "about": "Labore aliquip nulla est eiusmod amet Lorem duis fugiat duis do excepteur voluptate in non. Consequat nisi reprehenderit ullamco eu sit id consectetur commodo culpa consequat dolore aliqua. Amet nulla ut in laboris dolor do ad laboris eu commodo qui dolore pariatur. Et qui cillum anim dolore ipsum excepteur id laboris minim dolor.\r\n",+ "registered": "2014-03-26T22:07:14 +07:00",+ "latitude": 18.291259,+ "longitude": -86.22914,+ "tags": [+ "nisi",+ "ut",+ "dolore",+ "ullamco",+ "cupidatat",+ "nulla",+ "laborum"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Vonda Cote"+ },+ {+ "id": 1,+ "name": "Lewis Gonzales"+ },+ {+ "id": 2,+ "name": "Jacqueline Richmond"+ }+ ],+ "greeting": "Hello, Odessa Lawson! You have 4 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90f748a6195f1c2b42",+ "index": 69,+ "guid": "697c2775-d924-436d-ba9f-e21bd4fa0f73",+ "isActive": false,+ "balance": "$1,269.09",+ "picture": "http://placehold.it/32x32",+ "age": 40,+ "eyeColor": "green",+ "name": "Selena Nieves",+ "gender": "female",+ "company": "INTRAWEAR",+ "email": "selenanieves@intrawear.com",+ "phone": "+1 (862) 476-3196",+ "address": "101 Harkness Avenue, Worton, Connecticut, 400",+ "about": "Sunt aliquip exercitation dolor dolore nostrud anim enim anim est officia. Minim ea Lorem ullamco reprehenderit officia reprehenderit ex ex reprehenderit. Qui nulla ullamco consequat minim exercitation. Veniam id eu pariatur ut veniam dolore aliquip qui aliqua incididunt ut.\r\n",+ "registered": "2014-03-07T15:11:53 +08:00",+ "latitude": -43.588256,+ "longitude": 43.731157,+ "tags": [+ "duis",+ "duis",+ "reprehenderit",+ "ad",+ "magna",+ "excepteur",+ "officia"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Rutledge Hines"+ },+ {+ "id": 1,+ "name": "Carrillo Johnson"+ },+ {+ "id": 2,+ "name": "Morgan Parks"+ }+ ],+ "greeting": "Hello, Selena Nieves! You have 9 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90628ac7e339a407a5",+ "index": 70,+ "guid": "6ddd302b-fd62-47f9-aa8a-9fb2c35172c5",+ "isActive": true,+ "balance": "$2,185.43",+ "picture": "http://placehold.it/32x32",+ "age": 34,+ "eyeColor": "blue",+ "name": "Georgia Moran",+ "gender": "female",+ "company": "EARTHMARK",+ "email": "georgiamoran@earthmark.com",+ "phone": "+1 (970) 439-3884",+ "address": "848 Fay Court, Hayes, Maine, 7603",+ "about": "Ea do et excepteur dolor cupidatat nisi. Quis deserunt cupidatat duis enim eu deserunt anim enim. Cillum consectetur occaecat exercitation occaecat duis dolor voluptate officia exercitation irure. Occaecat magna proident enim exercitation veniam. Est commodo ullamco minim esse enim commodo ea commodo nulla et voluptate aliqua anim. Quis magna commodo nulla quis sit duis id et ex id ea dolore anim.\r\n",+ "registered": "2014-04-22T10:10:46 +07:00",+ "latitude": -78.673083,+ "longitude": 167.271688,+ "tags": [+ "non",+ "labore",+ "adipisicing",+ "cupidatat",+ "cupidatat",+ "quis",+ "aliquip"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Andrews Love"+ },+ {+ "id": 1,+ "name": "Brianna Yates"+ },+ {+ "id": 2,+ "name": "Jennifer Bass"+ }+ ],+ "greeting": "Hello, Georgia Moran! You have 10 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a901ec4ee748cbbc125",+ "index": 71,+ "guid": "0e5fc95f-e605-4baa-bc36-b2f795c42e03",+ "isActive": false,+ "balance": "$2,256.63",+ "picture": "http://placehold.it/32x32",+ "age": 22,+ "eyeColor": "blue",+ "name": "House Sargent",+ "gender": "male",+ "company": "FANFARE",+ "email": "housesargent@fanfare.com",+ "phone": "+1 (877) 416-3590",+ "address": "961 Olive Street, Sultana, Puerto Rico, 3764",+ "about": "Cillum minim aliquip sit nulla aute commodo pariatur reprehenderit aliqua laboris in sint velit. Qui irure ut nostrud elit aliqua reprehenderit tempor quis laboris. Voluptate enim eiusmod laborum est excepteur enim est. Veniam non magna ea proident deserunt ipsum Lorem adipisicing velit eiusmod. Culpa id ea non ex ad.\r\n",+ "registered": "2014-04-27T09:04:21 +07:00",+ "latitude": -54.902834,+ "longitude": 147.773359,+ "tags": [+ "cupidatat",+ "voluptate",+ "dolor",+ "excepteur",+ "exercitation",+ "id",+ "in"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Francis Alford"+ },+ {+ "id": 1,+ "name": "Berta Sparks"+ },+ {+ "id": 2,+ "name": "Laura Hahn"+ }+ ],+ "greeting": "Hello, House Sargent! You have 9 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90b51db1c7d287288e",+ "index": 72,+ "guid": "574450df-adad-4071-b642-0971f5f7928e",+ "isActive": true,+ "balance": "$2,263.30",+ "picture": "http://placehold.it/32x32",+ "age": 38,+ "eyeColor": "green",+ "name": "Roseann Lambert",+ "gender": "female",+ "company": "ROUGHIES",+ "email": "roseannlambert@roughies.com",+ "phone": "+1 (908) 551-2196",+ "address": "142 Girard Street, Levant, New Mexico, 2920",+ "about": "Aliquip ea elit anim aliqua in ea. Ex nisi nulla veniam amet. Occaecat pariatur qui consectetur consectetur anim ut anim cillum consectetur adipisicing pariatur. Cillum quis aliquip ad do in fugiat minim et ad labore sit ut aliqua cillum. Elit enim laboris incididunt laboris. Est in ullamco laboris deserunt aliqua veniam. Aute cillum culpa do dolore.\r\n",+ "registered": "2014-04-29T13:57:00 +07:00",+ "latitude": 0.812689,+ "longitude": 127.517728,+ "tags": [+ "veniam",+ "quis",+ "do",+ "aliqua",+ "deserunt",+ "id",+ "ut"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Amelia Dunlap"+ },+ {+ "id": 1,+ "name": "Benson Huff"+ },+ {+ "id": 2,+ "name": "Aimee Fisher"+ }+ ],+ "greeting": "Hello, Roseann Lambert! You have 6 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90285dfadf5a8ab1db",+ "index": 73,+ "guid": "cf2c0b72-e90e-43d1-a5ee-ff85e28272ec",+ "isActive": false,+ "balance": "$3,053.88",+ "picture": "http://placehold.it/32x32",+ "age": 20,+ "eyeColor": "brown",+ "name": "Althea Burgess",+ "gender": "female",+ "company": "RODEMCO",+ "email": "altheaburgess@rodemco.com",+ "phone": "+1 (946) 406-2326",+ "address": "127 Fleet Place, Northridge, Northern Mariana Islands, 2106",+ "about": "Ea aliquip mollit consectetur non sunt. Deserunt adipisicing sint non excepteur veniam. Sunt eu ad Lorem qui laborum labore. Dolor ut esse veniam dolor officia. Minim occaecat labore voluptate exercitation fugiat eu labore non dolor ipsum do magna qui incididunt.\r\n",+ "registered": "2014-03-16T23:19:14 +07:00",+ "latitude": -63.483213,+ "longitude": 118.593144,+ "tags": [+ "amet",+ "veniam",+ "consequat",+ "deserunt",+ "magna",+ "ea",+ "aliqua"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Delacruz Pollard"+ },+ {+ "id": 1,+ "name": "Kelly Washington"+ },+ {+ "id": 2,+ "name": "Irma Freeman"+ }+ ],+ "greeting": "Hello, Althea Burgess! You have 10 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a902435e7e0219ce954",+ "index": 74,+ "guid": "e3079855-52fe-494a-bb64-cf88934d1f84",+ "isActive": false,+ "balance": "$1,615.23",+ "picture": "http://placehold.it/32x32",+ "age": 28,+ "eyeColor": "brown",+ "name": "Ursula French",+ "gender": "female",+ "company": "KLUGGER",+ "email": "ursulafrench@klugger.com",+ "phone": "+1 (803) 454-3759",+ "address": "768 Bancroft Place, Layhill, Mississippi, 3591",+ "about": "Anim proident aliquip non amet. Dolore occaecat non irure cillum excepteur eu officia irure ea enim incididunt. Adipisicing ad esse voluptate duis dolor irure. Non sunt cillum est exercitation labore cillum minim consequat occaecat est aliqua. Ex adipisicing consequat aliqua pariatur est elit deserunt. Proident fugiat aliquip culpa magna ut deserunt incididunt eu enim esse fugiat eu consequat amet. Ad sit do Lorem aliquip enim ea magna.\r\n",+ "registered": "2014-08-01T00:12:36 +07:00",+ "latitude": -31.044528,+ "longitude": -131.432956,+ "tags": [+ "consequat",+ "enim",+ "nisi",+ "cupidatat",+ "est",+ "sint",+ "nostrud"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Mai Hudson"+ },+ {+ "id": 1,+ "name": "Erickson Perkins"+ },+ {+ "id": 2,+ "name": "Cleveland Armstrong"+ }+ ],+ "greeting": "Hello, Ursula French! You have 8 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a906ae58205e4d302e3",+ "index": 75,+ "guid": "f8b68baa-b922-4a5f-9d4a-fa7d9eee543c",+ "isActive": true,+ "balance": "$1,500.61",+ "picture": "http://placehold.it/32x32",+ "age": 29,+ "eyeColor": "blue",+ "name": "Lee Kelley",+ "gender": "male",+ "company": "INQUALA",+ "email": "leekelley@inquala.com",+ "phone": "+1 (947) 551-3499",+ "address": "973 Bayard Street, Orovada, North Dakota, 8499",+ "about": "Ullamco labore fugiat in minim duis duis reprehenderit deserunt eiusmod nostrud cillum laborum. Incididunt occaecat duis esse consectetur voluptate velit pariatur. Pariatur et qui sint anim sunt fugiat ut proident nulla fugiat. Nostrud ea sunt occaecat nulla qui id cupidatat proident ut.\r\n",+ "registered": "2014-11-01T01:18:21 +07:00",+ "latitude": -59.393379,+ "longitude": -110.276914,+ "tags": [+ "sit",+ "magna",+ "in",+ "consequat",+ "excepteur",+ "consequat",+ "Lorem"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Walton Daniels"+ },+ {+ "id": 1,+ "name": "Hammond Robbins"+ },+ {+ "id": 2,+ "name": "Evangelina Chaney"+ }+ ],+ "greeting": "Hello, Lee Kelley! You have 8 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a902a956e2130c70b9c",+ "index": 76,+ "guid": "3f62418d-23f0-4ed2-a76f-51645437223b",+ "isActive": false,+ "balance": "$2,477.19",+ "picture": "http://placehold.it/32x32",+ "age": 28,+ "eyeColor": "green",+ "name": "Miles Poole",+ "gender": "male",+ "company": "YOGASM",+ "email": "milespoole@yogasm.com",+ "phone": "+1 (866) 412-2294",+ "address": "744 Sutton Street, Richford, Vermont, 7668",+ "about": "Nostrud reprehenderit officia officia ex proident sint nulla sint quis duis laborum duis. Anim adipisicing officia officia anim aliquip incididunt culpa duis sint do ullamco ex consectetur. Commodo et tempor eu consequat laboris tempor ipsum magna elit labore consectetur excepteur.\r\n",+ "registered": "2014-07-20T11:37:28 +07:00",+ "latitude": 23.618997,+ "longitude": -80.142779,+ "tags": [+ "magna",+ "exercitation",+ "Lorem",+ "nostrud",+ "pariatur",+ "ut",+ "laborum"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Claudine Gill"+ },+ {+ "id": 1,+ "name": "Huff Kramer"+ },+ {+ "id": 2,+ "name": "Bryan Doyle"+ }+ ],+ "greeting": "Hello, Miles Poole! You have 10 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90357b2420c0dc0895",+ "index": 77,+ "guid": "ef7aa63d-53b9-4e85-ac36-4cfb1afd214a",+ "isActive": true,+ "balance": "$1,105.70",+ "picture": "http://placehold.it/32x32",+ "age": 39,+ "eyeColor": "green",+ "name": "Cohen Clemons",+ "gender": "male",+ "company": "EARBANG",+ "email": "cohenclemons@earbang.com",+ "phone": "+1 (936) 599-3992",+ "address": "952 Paerdegat Avenue, Frizzleburg, Rhode Island, 7905",+ "about": "Consequat exercitation fugiat ut labore. Ad magna sunt dolore magna nulla. Laborum deserunt magna eu incididunt magna occaecat ut sit aliqua nisi culpa dolor ullamco esse. Enim adipisicing proident proident enim qui est ad non. Ex proident sit irure cillum in nostrud veniam amet excepteur voluptate commodo eu eiusmod ullamco.\r\n",+ "registered": "2014-06-15T00:23:03 +07:00",+ "latitude": 78.28454,+ "longitude": 64.170517,+ "tags": [+ "non",+ "ex",+ "sit",+ "ipsum",+ "esse",+ "enim",+ "minim"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Sanchez Wolf"+ },+ {+ "id": 1,+ "name": "Trudy Melendez"+ },+ {+ "id": 2,+ "name": "Magdalena Hatfield"+ }+ ],+ "greeting": "Hello, Cohen Clemons! You have 3 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90ae5beac7dec2ba78",+ "index": 78,+ "guid": "1bccbb43-2801-4c99-a646-001622f3653c",+ "isActive": false,+ "balance": "$1,246.07",+ "picture": "http://placehold.it/32x32",+ "age": 35,+ "eyeColor": "blue",+ "name": "Evelyn Combs",+ "gender": "female",+ "company": "BITENDREX",+ "email": "evelyncombs@bitendrex.com",+ "phone": "+1 (937) 463-3648",+ "address": "498 Beayer Place, Caln, Michigan, 637",+ "about": "Laboris ipsum ea est nisi exercitation adipisicing commodo ea ipsum tempor. Laboris duis sit aliquip reprehenderit id cillum officia. Tempor velit reprehenderit adipisicing dolor ut qui id magna consequat. Fugiat proident sunt sit reprehenderit duis. Eu ipsum adipisicing eu magna cupidatat mollit esse.\r\n",+ "registered": "2014-06-14T20:28:41 +07:00",+ "latitude": 13.771679,+ "longitude": 58.844141,+ "tags": [+ "ex",+ "irure",+ "quis",+ "velit",+ "deserunt",+ "mollit",+ "irure"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Melton Wright"+ },+ {+ "id": 1,+ "name": "Letitia Osborn"+ },+ {+ "id": 2,+ "name": "Delgado Hebert"+ }+ ],+ "greeting": "Hello, Evelyn Combs! You have 7 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90a58e6a9e15665417",+ "index": 79,+ "guid": "6c039c25-e902-4121-9319-aa5e25f09b90",+ "isActive": true,+ "balance": "$1,839.17",+ "picture": "http://placehold.it/32x32",+ "age": 27,+ "eyeColor": "blue",+ "name": "Lakeisha Glover",+ "gender": "female",+ "company": "REALMO",+ "email": "lakeishaglover@realmo.com",+ "phone": "+1 (962) 444-3749",+ "address": "259 Homecrest Court, Villarreal, Oklahoma, 5463",+ "about": "Lorem cupidatat non elit mollit commodo tempor dolore sint qui officia fugiat mollit ex. Ea commodo minim labore commodo commodo sint occaecat eu aute est excepteur labore eiusmod ut. Fugiat voluptate laborum mollit aliqua ea. Ut fugiat culpa do velit non nisi voluptate exercitation. Duis elit velit adipisicing esse.\r\n",+ "registered": "2014-10-07T01:42:52 +07:00",+ "latitude": 7.777536,+ "longitude": -148.148716,+ "tags": [+ "officia",+ "Lorem",+ "eu",+ "eiusmod",+ "mollit",+ "duis",+ "exercitation"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Hodge Snider"+ },+ {+ "id": 1,+ "name": "Maritza Gilliam"+ },+ {+ "id": 2,+ "name": "Barbra Harding"+ }+ ],+ "greeting": "Hello, Lakeisha Glover! You have 5 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a904e60ffa71e64c330",+ "index": 80,+ "guid": "764804ce-2ded-4ab7-aef7-cc638d74a1f6",+ "isActive": true,+ "balance": "$3,096.79",+ "picture": "http://placehold.it/32x32",+ "age": 36,+ "eyeColor": "green",+ "name": "Hall Woodard",+ "gender": "male",+ "company": "HOTCAKES",+ "email": "hallwoodard@hotcakes.com",+ "phone": "+1 (923) 579-2251",+ "address": "678 Johnson Avenue, Nescatunga, West Virginia, 5718",+ "about": "Nulla Lorem proident incididunt nulla amet. Consectetur ea fugiat est adipisicing nisi exercitation ea irure. Id nisi anim culpa incididunt ea laborum. Non est aute anim deserunt ad cupidatat.\r\n",+ "registered": "2014-07-25T16:17:12 +07:00",+ "latitude": -72.300952,+ "longitude": 149.908938,+ "tags": [+ "magna",+ "fugiat",+ "laboris",+ "nulla",+ "tempor",+ "consequat",+ "officia"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Tessa Mccray"+ },+ {+ "id": 1,+ "name": "Hendricks Larson"+ },+ {+ "id": 2,+ "name": "Cecilia Mooney"+ }+ ],+ "greeting": "Hello, Hall Woodard! You have 1 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a9095c0ba3039bba2a0",+ "index": 81,+ "guid": "477bf131-1833-4ceb-a02d-367662e8a0ad",+ "isActive": true,+ "balance": "$3,975.04",+ "picture": "http://placehold.it/32x32",+ "age": 20,+ "eyeColor": "brown",+ "name": "Mccray Holman",+ "gender": "male",+ "company": "NETROPIC",+ "email": "mccrayholman@netropic.com",+ "phone": "+1 (888) 582-2650",+ "address": "930 Alton Place, Stouchsburg, Iowa, 8307",+ "about": "Officia laboris laboris ea magna nulla exercitation ullamco est magna proident cupidatat dolor. Et dolore fugiat nostrud elit in Lorem cillum eu incididunt ullamco irure eiusmod voluptate aliqua. Sint velit veniam nisi in amet incididunt ex et voluptate. Amet laborum sint fugiat nulla dolor adipisicing eiusmod ea. Labore amet nisi et pariatur duis non aliquip ea pariatur sit. Est eu dolore consequat ex quis qui adipisicing minim ea. Proident eiusmod enim irure cillum eu do laborum do voluptate occaecat id consectetur irure dolor.\r\n",+ "registered": "2014-07-15T14:32:20 +07:00",+ "latitude": 69.28999,+ "longitude": 20.24303,+ "tags": [+ "deserunt",+ "labore",+ "voluptate",+ "sint",+ "occaecat",+ "non",+ "sunt"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Ashley Mcintosh"+ },+ {+ "id": 1,+ "name": "Augusta Barr"+ },+ {+ "id": 2,+ "name": "Page Wiley"+ }+ ],+ "greeting": "Hello, Mccray Holman! You have 8 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a908bfd72d2f3594530",+ "index": 82,+ "guid": "e7128ea4-81e3-4888-ba11-4f3670e473ea",+ "isActive": false,+ "balance": "$3,306.06",+ "picture": "http://placehold.it/32x32",+ "age": 22,+ "eyeColor": "green",+ "name": "Sherri Villarreal",+ "gender": "female",+ "company": "TERRAGEN",+ "email": "sherrivillarreal@terragen.com",+ "phone": "+1 (881) 513-2832",+ "address": "922 Surf Avenue, Oberlin, Federated States Of Micronesia, 8301",+ "about": "Occaecat Lorem nostrud sint esse ullamco voluptate cillum sit aliquip sint nostrud. Velit aliqua cupidatat eu adipisicing sunt aute dolore cillum. Voluptate laboris exercitation magna non elit. Excepteur eiusmod enim amet fugiat quis. Anim cillum aute sit magna fugiat ut aliquip incididunt enim.\r\n",+ "registered": "2014-01-29T03:48:07 +08:00",+ "latitude": 70.685812,+ "longitude": -159.885272,+ "tags": [+ "adipisicing",+ "officia",+ "laborum",+ "ipsum",+ "voluptate",+ "sint",+ "cupidatat"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Vinson Berg"+ },+ {+ "id": 1,+ "name": "Emily Strong"+ },+ {+ "id": 2,+ "name": "Lori Gonzalez"+ }+ ],+ "greeting": "Hello, Sherri Villarreal! You have 1 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90ed7615708c5d1f8e",+ "index": 83,+ "guid": "cb7d9a4c-9739-43c8-b75e-0d3cdf462e89",+ "isActive": false,+ "balance": "$3,087.41",+ "picture": "http://placehold.it/32x32",+ "age": 28,+ "eyeColor": "brown",+ "name": "Little Nielsen",+ "gender": "male",+ "company": "LUDAK",+ "email": "littlenielsen@ludak.com",+ "phone": "+1 (826) 557-2684",+ "address": "842 Banner Avenue, Gadsden, Kentucky, 3196",+ "about": "Officia nostrud anim aliqua veniam ut. Non culpa et dolore nostrud elit esse sint mollit anim pariatur id velit irure culpa. Officia irure adipisicing velit velit culpa sunt proident occaecat irure voluptate ullamco. Labore mollit pariatur minim in cillum deserunt. Sint irure ex laborum et minim id ea fugiat excepteur velit veniam velit consequat sint. Culpa anim velit elit officia irure exercitation ex labore est amet. Do do eiusmod ipsum officia veniam laboris irure sint eiusmod non cillum eiusmod.\r\n",+ "registered": "2014-09-19T15:02:29 +07:00",+ "latitude": 26.743234,+ "longitude": -53.174043,+ "tags": [+ "et",+ "sint",+ "culpa",+ "dolore",+ "ea",+ "irure",+ "excepteur"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Gillespie Branch"+ },+ {+ "id": 1,+ "name": "Cantu Kent"+ },+ {+ "id": 2,+ "name": "Nell Meyer"+ }+ ],+ "greeting": "Hello, Little Nielsen! You have 5 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a909137471ca6b126c8",+ "index": 84,+ "guid": "169b0cbf-781c-4b46-8285-e18b3aa6bc0e",+ "isActive": true,+ "balance": "$2,853.96",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "green",+ "name": "Kristi Marquez",+ "gender": "female",+ "company": "RONELON",+ "email": "kristimarquez@ronelon.com",+ "phone": "+1 (838) 414-3765",+ "address": "566 Love Lane, Fresno, New Jersey, 5219",+ "about": "Proident enim commodo ut nisi minim esse eiusmod nisi irure consequat proident voluptate. Culpa ut sunt incididunt sint minim duis excepteur nulla cupidatat ullamco proident nisi ex enim. Qui culpa ex velit do pariatur Lorem dolor ad labore adipisicing magna sunt voluptate dolore. Lorem minim commodo non amet. Nulla reprehenderit consectetur ad nisi voluptate. Ea consectetur deserunt dolore ut. Esse duis consequat reprehenderit cillum commodo consequat ex consectetur do sint velit non deserunt.\r\n",+ "registered": "2014-02-21T07:19:48 +08:00",+ "latitude": 38.750345,+ "longitude": -111.349096,+ "tags": [+ "minim",+ "minim",+ "occaecat",+ "tempor",+ "dolore",+ "fugiat",+ "laborum"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Eddie Soto"+ },+ {+ "id": 1,+ "name": "Valencia Serrano"+ },+ {+ "id": 2,+ "name": "Sears Richards"+ }+ ],+ "greeting": "Hello, Kristi Marquez! You have 3 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90deb8bb21d9c88b7a",+ "index": 85,+ "guid": "58c6180e-8bc6-4ae0-9988-52df23beedac",+ "isActive": false,+ "balance": "$2,028.59",+ "picture": "http://placehold.it/32x32",+ "age": 39,+ "eyeColor": "blue",+ "name": "Callie Sweeney",+ "gender": "female",+ "company": "POLARIA",+ "email": "calliesweeney@polaria.com",+ "phone": "+1 (999) 576-3446",+ "address": "278 Gunnison Court, Wakulla, Nevada, 3605",+ "about": "Minim non eu sint culpa. Non irure ea eiusmod est dolore id culpa laborum ex aliquip et eu. Laborum occaecat labore incididunt et ipsum adipisicing cupidatat eu consectetur reprehenderit quis dolor.\r\n",+ "registered": "2014-11-06T17:55:38 +08:00",+ "latitude": 22.578553,+ "longitude": 70.713617,+ "tags": [+ "veniam",+ "ad",+ "aliqua",+ "id",+ "quis",+ "esse",+ "est"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Cochran Raymond"+ },+ {+ "id": 1,+ "name": "Perry Pugh"+ },+ {+ "id": 2,+ "name": "Walsh Cummings"+ }+ ],+ "greeting": "Hello, Callie Sweeney! You have 8 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a9092b4caeee42e4083",+ "index": 86,+ "guid": "b37a99a1-89ea-4257-bd5c-f8070c6e5d72",+ "isActive": false,+ "balance": "$2,333.35",+ "picture": "http://placehold.it/32x32",+ "age": 27,+ "eyeColor": "brown",+ "name": "Henson Parrish",+ "gender": "male",+ "company": "MANTRO",+ "email": "hensonparrish@mantro.com",+ "phone": "+1 (983) 409-3702",+ "address": "749 Malbone Street, Century, California, 6571",+ "about": "Pariatur nisi magna laboris ipsum ad sint. Exercitation sit id reprehenderit fugiat ea dolor. Duis exercitation voluptate nulla duis enim culpa eiusmod nulla mollit et occaecat eu Lorem.\r\n",+ "registered": "2014-06-21T02:15:00 +07:00",+ "latitude": 42.27087,+ "longitude": 88.230275,+ "tags": [+ "sunt",+ "excepteur",+ "veniam",+ "cillum",+ "sunt",+ "consequat",+ "ullamco"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Dunn Cantrell"+ },+ {+ "id": 1,+ "name": "Mendoza Keller"+ },+ {+ "id": 2,+ "name": "Josefa Green"+ }+ ],+ "greeting": "Hello, Henson Parrish! You have 7 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a9001009b488b9deadf",+ "index": 87,+ "guid": "4a8e033a-6160-44a0-b6f6-e07f11455db9",+ "isActive": false,+ "balance": "$2,886.19",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "blue",+ "name": "Mcgowan Hogan",+ "gender": "male",+ "company": "MAGNEMO",+ "email": "mcgowanhogan@magnemo.com",+ "phone": "+1 (816) 507-2353",+ "address": "979 Reed Street, Roberts, Maryland, 9773",+ "about": "Sunt sint labore aliqua nisi ipsum mollit. Lorem aliquip nisi Lorem eu velit. Laborum reprehenderit minim cillum culpa cupidatat commodo do aute dolore. Sunt ullamco consectetur ex officia anim fugiat quis fugiat laboris est quis officia aliqua pariatur. Adipisicing nulla culpa officia ut reprehenderit ea cupidatat.\r\n",+ "registered": "2014-05-26T12:57:18 +07:00",+ "latitude": -24.348796,+ "longitude": 25.886101,+ "tags": [+ "ex",+ "ullamco",+ "non",+ "ea",+ "enim",+ "quis",+ "ipsum"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Terry Burton"+ },+ {+ "id": 1,+ "name": "Cara Estes"+ },+ {+ "id": 2,+ "name": "Johanna Dillard"+ }+ ],+ "greeting": "Hello, Mcgowan Hogan! You have 1 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a9021cae47006152c91",+ "index": 88,+ "guid": "ebae8f41-1ba7-4f91-8d61-1a1a0d6b515f",+ "isActive": false,+ "balance": "$2,168.49",+ "picture": "http://placehold.it/32x32",+ "age": 25,+ "eyeColor": "brown",+ "name": "Riddle Alvarado",+ "gender": "male",+ "company": "INTERLOO",+ "email": "riddlealvarado@interloo.com",+ "phone": "+1 (892) 530-2012",+ "address": "488 Loring Avenue, Homeworth, Washington, 8337",+ "about": "Officia labore commodo eu consectetur. Consectetur consequat voluptate minim dolor do anim magna deserunt ullamco. Mollit laborum eiusmod veniam velit officia dolore dolore in ex veniam officia eu elit fugiat. Labore non in Lorem nulla irure ea id cupidatat eu consectetur. Tempor non quis eu nulla aliquip proident elit commodo duis laboris laborum eu amet occaecat.\r\n",+ "registered": "2014-11-13T11:12:08 +08:00",+ "latitude": 21.377099,+ "longitude": 128.211659,+ "tags": [+ "ex",+ "excepteur",+ "magna",+ "enim",+ "magna",+ "et",+ "incididunt"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Elisa Vinson"+ },+ {+ "id": 1,+ "name": "Peterson Reynolds"+ },+ {+ "id": 2,+ "name": "Mason Odonnell"+ }+ ],+ "greeting": "Hello, Riddle Alvarado! You have 1 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a901459251e4d519953",+ "index": 89,+ "guid": "6fe0652a-7055-47d0-8b6a-8bc3b3f6a7d0",+ "isActive": true,+ "balance": "$1,638.04",+ "picture": "http://placehold.it/32x32",+ "age": 29,+ "eyeColor": "blue",+ "name": "Stone Maynard",+ "gender": "male",+ "company": "CONJURICA",+ "email": "stonemaynard@conjurica.com",+ "phone": "+1 (827) 532-2021",+ "address": "631 Orient Avenue, Homestead, Utah, 8151",+ "about": "In voluptate voluptate veniam reprehenderit dolor est ut est voluptate dolore occaecat voluptate. Laboris cillum ex aliquip quis dolor qui qui fugiat sit. Veniam magna dolor mollit sint laborum duis id duis aliqua dolore reprehenderit qui et. Irure cupidatat ea sunt anim amet mollit adipisicing id sint deserunt veniam irure. Reprehenderit elit mollit do ex reprehenderit ipsum aliqua qui. Ea non eiusmod officia laboris dolor tempor deserunt elit velit ex aliqua. Duis reprehenderit duis duis elit irure elit dolore dolore.\r\n",+ "registered": "2014-05-26T12:55:16 +07:00",+ "latitude": -20.476755,+ "longitude": 76.876321,+ "tags": [+ "fugiat",+ "dolore",+ "consequat",+ "do",+ "esse",+ "consectetur",+ "anim"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Mckenzie Bartlett"+ },+ {+ "id": 1,+ "name": "Villarreal Welch"+ },+ {+ "id": 2,+ "name": "Amparo Kelly"+ }+ ],+ "greeting": "Hello, Stone Maynard! You have 5 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a9015625be6710ded3e",+ "index": 90,+ "guid": "d079e795-b71e-446b-91f8-6347ca0e2e57",+ "isActive": false,+ "balance": "$1,156.54",+ "picture": "http://placehold.it/32x32",+ "age": 28,+ "eyeColor": "blue",+ "name": "Baird Jones",+ "gender": "male",+ "company": "KNEEDLES",+ "email": "bairdjones@kneedles.com",+ "phone": "+1 (898) 574-3748",+ "address": "890 Lancaster Avenue, Falconaire, Wisconsin, 9406",+ "about": "Officia veniam sunt minim ex tempor labore consequat laborum adipisicing officia. Incididunt enim excepteur anim et do cupidatat magna excepteur culpa. Dolore enim ea excepteur non commodo aliqua nostrud commodo exercitation dolor duis. Consectetur consequat ullamco in esse fugiat pariatur anim mollit aliqua aliquip qui. Voluptate cupidatat ipsum labore aliquip fugiat cillum amet sunt voluptate occaecat occaecat nostrud.\r\n",+ "registered": "2014-01-22T19:38:09 +08:00",+ "latitude": -30.096555,+ "longitude": -119.933566,+ "tags": [+ "occaecat",+ "qui",+ "enim",+ "in",+ "pariatur",+ "irure",+ "officia"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Gail Flynn"+ },+ {+ "id": 1,+ "name": "Sanford Harmon"+ },+ {+ "id": 2,+ "name": "Noble Chambers"+ }+ ],+ "greeting": "Hello, Baird Jones! You have 3 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a90b147f5343b9ce16b",+ "index": 91,+ "guid": "af036dfd-72dd-451e-b93d-6dceea4796c4",+ "isActive": false,+ "balance": "$3,703.12",+ "picture": "http://placehold.it/32x32",+ "age": 33,+ "eyeColor": "blue",+ "name": "Leila Gay",+ "gender": "female",+ "company": "ZOXY",+ "email": "leilagay@zoxy.com",+ "phone": "+1 (845) 467-2535",+ "address": "800 Little Street, Troy, Louisiana, 233",+ "about": "Ea aliqua excepteur duis est velit eiusmod irure est eiusmod non elit. Consequat nostrud elit ullamco minim labore deserunt commodo. Mollit amet duis laboris mollit est ex aliquip. Minim et veniam reprehenderit voluptate aliqua id officia excepteur consequat fugiat non ex eu. Fugiat officia cupidatat pariatur voluptate excepteur in.\r\n",+ "registered": "2014-08-02T18:50:58 +07:00",+ "latitude": 59.481938,+ "longitude": 141.038749,+ "tags": [+ "ipsum",+ "commodo",+ "velit",+ "sit",+ "aliquip",+ "ullamco",+ "nisi"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Conway Summers"+ },+ {+ "id": 1,+ "name": "Deirdre Moody"+ },+ {+ "id": 2,+ "name": "Curtis Dickerson"+ }+ ],+ "greeting": "Hello, Leila Gay! You have 10 unread messages.",+ "favoriteFruit": "apple"+ },+ {+ "_id": "54727a90ffed9e529a6fa6b2",+ "index": 92,+ "guid": "7deb0cd2-5374-40c4-a38d-060ef674b2df",+ "isActive": true,+ "balance": "$2,980.94",+ "picture": "http://placehold.it/32x32",+ "age": 20,+ "eyeColor": "brown",+ "name": "Alma England",+ "gender": "female",+ "company": "SOLAREN",+ "email": "almaengland@solaren.com",+ "phone": "+1 (941) 595-3246",+ "address": "727 Covert Street, Nutrioso, Florida, 9152",+ "about": "Commodo quis occaecat voluptate tempor commodo non ipsum quis tempor pariatur elit. Ea fugiat velit dolor ea et occaecat eu ad aute ipsum. In sunt ad reprehenderit duis. Qui deserunt voluptate proident eu officia laborum pariatur incididunt id nisi. Eiusmod adipisicing do pariatur et incididunt aliquip consectetur.\r\n",+ "registered": "2014-08-08T20:51:29 +07:00",+ "latitude": 70.990007,+ "longitude": -119.193428,+ "tags": [+ "irure",+ "cillum",+ "incididunt",+ "nisi",+ "magna",+ "ullamco",+ "ex"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Downs Keith"+ },+ {+ "id": 1,+ "name": "Dawn Velazquez"+ },+ {+ "id": 2,+ "name": "Deanna Simpson"+ }+ ],+ "greeting": "Hello, Alma England! You have 9 unread messages.",+ "favoriteFruit": "strawberry"+ },+ {+ "_id": "54727a9075e4734b622a166a",+ "index": 93,+ "guid": "c0adc5f1-039a-4b52-a8cf-0196f3c23129",+ "isActive": true,+ "balance": "$2,658.69",+ "picture": "http://placehold.it/32x32",+ "age": 21,+ "eyeColor": "brown",+ "name": "Lou Rose",+ "gender": "female",+ "company": "INFOTRIPS",+ "email": "lourose@infotrips.com",+ "phone": "+1 (845) 564-3943",+ "address": "343 Krier Place, Evergreen, Indiana, 5249",+ "about": "Tempor ullamco id reprehenderit sunt veniam incididunt laboris. Ea ut officia do velit dolor officia Lorem consectetur nisi velit nisi. Aliquip dolore minim sint deserunt deserunt est.\r\n",+ "registered": "2014-04-22T07:46:26 +07:00",+ "latitude": 12.216368,+ "longitude": 8.875707,+ "tags": [+ "velit",+ "consectetur",+ "Lorem",+ "est",+ "adipisicing",+ "ad",+ "ullamco"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Coleen Foley"+ },+ {+ "id": 1,+ "name": "Boone Fitzpatrick"+ },+ {+ "id": 2,+ "name": "Elise Osborne"+ }+ ],+ "greeting": "Hello, Lou Rose! You have 5 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a90512b4f65287789e9",+ "index": 94,+ "guid": "26d470db-29c3-4c14-894b-5654462385a5",+ "isActive": false,+ "balance": "$2,751.47",+ "picture": "http://placehold.it/32x32",+ "age": 23,+ "eyeColor": "blue",+ "name": "Velez Wong",+ "gender": "male",+ "company": "FRANSCENE",+ "email": "velezwong@franscene.com",+ "phone": "+1 (821) 577-3492",+ "address": "197 Huron Street, Hilltop, New Hampshire, 6969",+ "about": "Minim id ullamco ullamco do proident Lorem commodo tempor ea. Est ut id non proident eiusmod. Deserunt fugiat enim culpa veniam sint.\r\n",+ "registered": "2014-07-21T05:23:01 +07:00",+ "latitude": -37.262537,+ "longitude": 132.661281,+ "tags": [+ "culpa",+ "non",+ "elit",+ "nulla",+ "laboris",+ "elit",+ "ex"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Charmaine Curry"+ },+ {+ "id": 1,+ "name": "Clara Randall"+ },+ {+ "id": 2,+ "name": "Lauren Jacobs"+ }+ ],+ "greeting": "Hello, Velez Wong! You have 4 unread messages.",+ "favoriteFruit": "banana"+ },+ {+ "_id": "54727a9095dc4743a5a84bd7",+ "index": 95,+ "guid": "1d1b9166-affc-4d15-ab60-b2edc51f29b4",+ "isActive": true,+ "balance": "$1,063.39",+ "picture": "http://placehold.it/32x32",+ "age": 22,+ "eyeColor": "brown",+ "name": "Catalina Baxter",+ "gender": "female",+ "company": "GAZAK",+ "email": "catalinabaxter@gazak.com",+ "phone": "+1 (839) 435-3437",+ "address": "904 Miller Avenue, Callaghan, Kansas, 7896",+ "about": "Ut ex exercitation commodo sint sint ipsum ea incididunt. Sunt nostrud tempor sint occaecat qui laborum culpa ipsum ullamco veniam est excepteur nostrud. Consequat occaecat id adipisicing esse culpa occaecat. Proident veniam laboris aute minim dolore eiusmod nulla minim elit sint.\r\n",+ "registered": "2014-05-02T10:13:41 +07:00",+ "latitude": 18.545597,+ "longitude": -99.991313,+ "tags": [+ "do",+ "proident",+ "reprehenderit",+ "minim",+ "cillum",+ "quis",+ "esse"+ ],+ "friends": [+ {+ "id": 0,+ "name": "Monique Wilcox"+ },+ {+ "id": 1,+ "name": "Hilda Craig"+ },+ {+ "id": 2,+ "name": "Leola Higgins"+ }+ ],+ "greeting": "Hello, Catalina Baxter! You have 10 unread messages.",+ "favoriteFruit": "apple"+ }+]
+ benchmarks/json-data/dates-fract.json view
@@ -0,0 +1,1 @@+["2015-02-02T09:10:11.123Z","2015-02-03T09:10:11.000+0000","2014-01-02T09:10:11.333Z","2014-01-03T02:09:12.000-02:00","2013-05-06T07:08:09.444Z","2015-02-02T09:10:11.66+03:00","2015-02-03T09:10:11.66Z","2014-01-02T09:10:11.66-1200","2014-01-03T02:09:12.66Z","2013-05-06T07:08:09.66+00:00"]
+ benchmarks/json-data/dates.json view
@@ -0,0 +1,1 @@+["2015-02-02T09:10:11Z","2015-02-03T09:10:11+0000","2014-01-02T09:10:11Z","2014-01-03T02:09:12-0300","2013-05-06T07:08:09Z","2015-02-02T09:10:11+04:00","2015-02-03T09:10:11Z","2014-01-02T09:10:11-11:45","2014-01-03T02:09:12Z","2013-05-06T07:08:09+0000"]
benchmarks/json-data/jp10.json view
benchmarks/json-data/jp100.json view
benchmarks/json-data/jp50.json view
benchmarks/json-data/twitter1.json view
benchmarks/json-data/twitter10.json view
benchmarks/json-data/twitter100.json view
@@ -1,1 +1,1 @@-{"results":[{"from_user_id_str":"3646730","profile_image_url":"http://a3.twimg.com/profile_images/404973767/avatar_normal.jpg","created_at":"Wed, 26 Jan 2011 04:35:07 +0000","from_user":"nicolaslara","id_str":"30121530767708160","metadata":{"result_type":"recent"},"to_user_id":18616016,"text":"@josej30 Python y Clojure. Obviamente son diferentes, y cada uno tiene sus ventajas y desventajas. De Haskell faltar\u00eda pattern matching","id":30121530767708160,"from_user_id":3646730,"to_user":"josej30","geo":null,"iso_language_code":"es","to_user_id_str":"18616016","source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"207858021","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 04:30:38 +0000","from_user":"pboudarga","id_str":"30120402839666689","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Rolla Sushi Grill (27737 Bouquet Canyon Road, #106, Btw Haskell Canyon and Rosedell Drive, Saugus) http://4sq.com/gqqdhs","id":30120402839666689,"from_user_id":207858021,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"69988683","profile_image_url":"http://a0.twimg.com/profile_images/1211955817/avatar_7888_normal.gif","created_at":"Wed, 26 Jan 2011 04:25:23 +0000","from_user":"YNK33","id_str":"30119083059978240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"hsndfile 0.5.0: Free and open source Haskell bindings for libsndfile http://bit.ly/gHaBWG Mac Os","id":30119083059978240,"from_user_id":69988683,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"81492","profile_image_url":"http://a1.twimg.com/profile_images/423894208/Picture_7_normal.jpg","created_at":"Wed, 26 Jan 2011 04:24:28 +0000","from_user":"satzz","id_str":"30118851488251904","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Emacs\u306e\u30e2\u30fc\u30c9\u8868\u793a\u304c\u4eca(Ruby Controller Outputz RoR Flymake REl hs)\u3068\u306a\u3063\u3066\u3066\u3088\u304f\u308f\u304b\u3089\u306a\u3044\u3093\u3060\u3051\u3069\u6700\u5f8c\u306eREl\u3068\u304bhs\u3063\u3066\u4f55\u3060\u308d\u3046\u2026haskell\u3068\u304b2\u5e74\u4ee5\u4e0a\u66f8\u3044\u3066\u306a\u3044\u3051\u3069\u2026","id":30118851488251904,"from_user_id":81492,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"9518356","profile_image_url":"http://a2.twimg.com/profile_images/119165723/ocaml-icon_normal.png","created_at":"Wed, 26 Jan 2011 04:19:19 +0000","from_user":"planet_ocaml","id_str":"30117557788741632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I so miss #haskell type classes in #ocaml - i want to do something like refinement. Also why does ocaml not have... http://bit.ly/geYRwt","id":30117557788741632,"from_user_id":9518356,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"218059","profile_image_url":"http://a1.twimg.com/profile_images/1053837723/twitter-icon9_normal.jpg","created_at":"Wed, 26 Jan 2011 04:16:32 +0000","from_user":"aprikip","id_str":"30116854940835840","metadata":{"result_type":"recent"},"to_user_id":null,"text":"yatex-mode\u3084haskell-mode\u306e\u3053\u3068\u3067\u3059\u306d\u3001\u308f\u304b\u308a\u307e\u3059\u3002","id":30116854940835840,"from_user_id":218059,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sites.google.com/site/yorufukurou/" rel="nofollow">YoruFukurou</a>"},{"from_user_id_str":"216363","profile_image_url":"http://a1.twimg.com/profile_images/72454310/Tim-Avatar_normal.png","created_at":"Wed, 26 Jan 2011 04:15:30 +0000","from_user":"dysinger","id_str":"30116594684264448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell in Hawaii tonight for me... #fun","id":30116594684264448,"from_user_id":216363,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.nambu.com/" rel="nofollow">Nambu</a>"},{"from_user_id_str":"1774820","profile_image_url":"http://a2.twimg.com/profile_images/61169291/dan_desert_thumb_normal.jpg","created_at":"Wed, 26 Jan 2011 04:13:36 +0000","from_user":"DanMil","id_str":"30116117682851840","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire @tomheon Haskell isn't a language, it's a belief system. A seductive one...","id":30116117682851840,"from_user_id":1774820,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"659256","profile_image_url":"http://a0.twimg.com/profile_images/746976711/angular-final_normal.jpg","created_at":"Wed, 26 Jan 2011 04:11:06 +0000","from_user":"djspiewak","id_str":"30115488931520512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"One of the very nice things about Haskell as opposed to SML is the reduced proliferation of identifiers (e.g. andb, orb, etc). #typeclasses","id":30115488931520512,"from_user_id":659256,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 04:06:12 +0000","from_user":"listwarenet","id_str":"30114255890026496","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84752-re-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Re: Haskell-c","id":30114255890026496,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 04:01:29 +0000","from_user":"ojrac","id_str":"30113067333324800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tomheon: @ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30113067333324800,"from_user_id":1594784,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"207589736","profile_image_url":"http://a3.twimg.com/profile_images/1225527428/headshot_1_normal.jpg","created_at":"Wed, 26 Jan 2011 04:00:13 +0000","from_user":"ashleevelazq101","id_str":"30112747555397632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/dONnpn","id":30112747555397632,"from_user_id":207589736,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"Hackage","id_str":"30112192346984448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112192346984448,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"aapnoot","id_str":"30112191881420800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112191881420800,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"8530482","profile_image_url":"http://a2.twimg.com/profile_images/137867266/n608671563_7396_normal.jpg","created_at":"Wed, 26 Jan 2011 03:50:12 +0000","from_user":"jeffmclamb","id_str":"30110229207187456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Angel - daemon to run and monitor processes like daemontools or god, written in Haskell http://ff.im/-wNyLk","id":30110229207187456,"from_user_id":8530482,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://friendfeed.com" rel="nofollow">FriendFeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:46:01 +0000","from_user":"tomheon","id_str":"30109174645919744","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30109174645919744,"from_user_id":177539201,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 03:44:34 +0000","from_user":"ojrac","id_str":"30108808684503040","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire @tomheon Why are you making me curious about Haskell? I LIKE not knowing what monad means!!","id":30108808684503040,"from_user_id":1594784,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"23750094","profile_image_url":"http://a0.twimg.com/profile_images/951373780/Moeinthecar_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:54 +0000","from_user":"shokalshab","id_str":"30108140443795456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Magnitude Cheer @ Gymnastics Olympica USA (7735 Haskell Ave., btw Saticoy & Strathern, Van Nuys) http://4sq.com/gmXfaL","id":30108140443795456,"from_user_id":23750094,"geo":null,"iso_language_code":"en","place":{"id":"4e4a2a2f86cb2946","type":"poi","full_name":"Gymnastics Olympica USA, Van Nuys"},"to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"8135112","profile_image_url":"http://a0.twimg.com/profile_images/1165240350/LIMITED_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:35 +0000","from_user":"Claricei","id_str":"30108059208515584","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @kristenmchugh22: @KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30108059208515584,"from_user_id":8135112,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:40:02 +0000","from_user":"chewedwire","id_str":"30107670367182848","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon Cool, I'll take a look. I feel like I should mention this: http://bit.ly/hVstDM","id":30107670367182848,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"8679778","profile_image_url":"http://a3.twimg.com/profile_images/1195318056/me_nyc_12_18_10_icon_normal.jpg","created_at":"Wed, 26 Jan 2011 03:38:42 +0000","from_user":"kristenmchugh22","id_str":"30107332381777920","metadata":{"result_type":"recent"},"to_user_id":756269,"text":"@KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30107332381777920,"from_user_id":8679778,"to_user":"KeithOlbermann","geo":null,"iso_language_code":"en","to_user_id_str":"756269","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"103316559","profile_image_url":"http://a1.twimg.com/profile_images/1179458751/bc3beab4-d59d-4e78-b13b-50747986cfa2_normal.png","created_at":"Wed, 26 Jan 2011 03:36:15 +0000","from_user":"cityslikr","id_str":"30106719153557504","metadata":{"result_type":"recent"},"to_user_id":null,"text":""Social safety net into a hammock." So says Eddie Haskell with the GOP response. #SOTU","id":30106719153557504,"from_user_id":103316559,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry\u00ae</a>"},{"from_user_id_str":"169063143","profile_image_url":"http://a0.twimg.com/profile_images/1160506212/9697_1_normal.gif","created_at":"Wed, 26 Jan 2011 03:31:52 +0000","from_user":"wrkforce_safety","id_str":"30105614919143424","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/gA60C1","id":30105614919143424,"from_user_id":169063143,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:29:40 +0000","from_user":"tomheon","id_str":"30105060960632832","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire Great book on Haskell: http://oreilly.com/catalog/9780596514983","id":30105060960632832,"from_user_id":177539201,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"782692","profile_image_url":"http://a0.twimg.com/profile_images/1031304589/Profile.2007.1_normal.jpg","created_at":"Wed, 26 Jan 2011 03:29:19 +0000","from_user":"turnageb","id_str":"30104974591533057","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @ovillalon: Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104974591533057,"from_user_id":782692,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:28:04 +0000","from_user":"chewedwire","id_str":"30104657267265536","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon I always loved the pattern matching in SML and it looks like Haskell is MUCH better at it. I'm messing around now at tryhaskell.org","id":30104657267265536,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"12834082","profile_image_url":"http://a3.twimg.com/profile_images/1083036140/mugshot_normal.png","created_at":"Wed, 26 Jan 2011 03:28:01 +0000","from_user":"ovillalon","id_str":"30104647213518848","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104647213518848,"from_user_id":12834082,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:26:02 +0000","from_user":"goodfox","id_str":"30104146455560192","metadata":{"result_type":"recent"},"to_user_id":10226179,"text":"@billykeene22 Bordeaux is one of my heroes. I was so excited when he accepted the invitation to campus. He's been a great friend to Haskell.","id":30104146455560192,"from_user_id":13540930,"to_user":"billykeene22","geo":null,"iso_language_code":"en","to_user_id_str":"10226179","source":"<a href="http://www.ubertwitter.com/bb/download.php" rel="nofollow">\u00dcberTwitter</a>"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 03:25:18 +0000","from_user":"josej30","id_str":"30103962313031681","metadata":{"result_type":"recent"},"to_user_id":14870909,"text":"@cris7ian Ahh bueno multiparadigma ya es respetable :) Empezar\u00e9 a explotar la parte funcional de los lenguajes ahora #Haskell","id":30103962313031681,"from_user_id":18616016,"to_user":"Cris7ian","geo":null,"iso_language_code":"es","to_user_id_str":"14870909","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"14870909","profile_image_url":"http://a2.twimg.com/profile_images/1176930429/oso_yo_normal.png","created_at":"Wed, 26 Jan 2011 03:23:43 +0000","from_user":"Cris7ian","id_str":"30103562360983553","metadata":{"result_type":"recent"},"to_user_id":18616016,"text":"@josej30 hahaha no, es multiparadigma y es bastante lazy. Nothing like haskell, pero s\u00ed, el de Flash","id":30103562360983553,"from_user_id":14870909,"to_user":"josej30","geo":null,"iso_language_code":"es","to_user_id_str":"18616016","source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"2421643","profile_image_url":"http://a0.twimg.com/profile_images/1190361665/ernestgrumbles-17_normal.jpg","created_at":"Wed, 26 Jan 2011 03:20:24 +0000","from_user":"ernestgrumbles","id_str":"30102730756333568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Wow... WolframAlpha did not know who Eddie Haskell is. Guess I'll never use that "knowledge engine" again.","id":30102730756333568,"from_user_id":2421643,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:14:21 +0000","from_user":"chewedwire","id_str":"30101204428132352","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon How is Haskell better/different from CL or Scheme? I honestly don't know, although I'm becoming more curious.","id":30101204428132352,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:06:54 +0000","from_user":"goodfox","id_str":"30099329809129473","metadata":{"result_type":"recent"},"to_user_id":null,"text":"A day of vision & speeches. #SOTU now. And a wonderful Haskell Convocation address earlier today by Sinte Gleske President Lionel Bordeaux.","id":30099329809129473,"from_user_id":13540930,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.ubertwitter.com/bb/download.php" rel="nofollow">\u00dcberTwitter</a>"},{"from_user_id_str":"119185220","profile_image_url":"http://a0.twimg.com/profile_images/1089027228/dfg_normal.jpg","created_at":"Wed, 26 Jan 2011 03:03:38 +0000","from_user":"LaLiciouz_03","id_str":"30098510623805440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"The Game with the girl room 330 Haskell follow us...","id":30098510623805440,"from_user_id":119185220,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 02:57:25 +0000","from_user":"josej30","id_str":"30096946144215040","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Voy a extra\u00f1ar Haskell cuando regrese al mundo imperativo. Hay alg\u00fan lenguaje imperativo que tenga este poder funcional? #ci3661","id":30096946144215040,"from_user_id":18616016,"geo":null,"iso_language_code":"es","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 02:55:32 +0000","from_user":"Hackage","id_str":"30096471814574080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"comonad-transformers 0.9.0, added by EdwardKmett: Haskell 98 comonad transformers http://bit.ly/h6xIsf","id":30096471814574080,"from_user_id":17671137,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 02:48:12 +0000","from_user":"tomheon","id_str":"30094626920603649","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Every time I look at Haskell I love it more.","id":30094626920603649,"from_user_id":177539201,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"60792568","profile_image_url":"http://a0.twimg.com/profile_images/1203647517/glenda-flash_normal.jpg","created_at":"Wed, 26 Jan 2011 02:40:42 +0000","from_user":"r_takaishi","id_str":"30092735935422464","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u3088\u308aD\u8a00\u8a9e\u304c\u4e0a\u3068\u306f\u601d\u308f\u306a\u304b\u3063\u305f\uff0e http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html","id":30092735935422464,"from_user_id":60792568,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twmode.sf.net/" rel="nofollow">twmode</a>"},{"from_user_id_str":"160145510","profile_image_url":"http://a0.twimg.com/profile_images/1218108166/going_galt_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:31 +0000","from_user":"wtp1787","id_str":"30092439653974018","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @KLSouth: Eddie Haskell Goes to Washington... "You look really nice tonight, Ms Cleaver"","id":30092439653974018,"from_user_id":160145510,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"96616016","profile_image_url":"http://a1.twimg.com/profile_images/1196978169/Picture0002_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:20 +0000","from_user":"MelissaRNMBA","id_str":"30092392203816960","metadata":{"result_type":"recent"},"to_user_id":14862975,"text":"@KLSouth At least Eddie Haskell was entertaining.","id":30092392203816960,"from_user_id":96616016,"to_user":"KLSouth","geo":null,"iso_language_code":"en","to_user_id_str":"14862975","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"14862975","profile_image_url":"http://a0.twimg.com/profile_images/421596393/kls_4_normal.JPG","created_at":"Wed, 26 Jan 2011 02:38:29 +0000","from_user":"KLSouth","id_str":"30092178327871489","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Eddie Haskell Goes to Washington... "You look really nice tonight, Ms Cleaver"","id":30092178327871489,"from_user_id":14862975,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 02:36:17 +0000","from_user":"listwarenet","id_str":"30091626869161984","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84641-haskell-beginners-wildcards-in-expressions.html Haskell-beginners - Wild","id":30091626869161984,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"24538048","profile_image_url":"http://a2.twimg.com/profile_images/1117267605/rope_normal.jpg","created_at":"Wed, 26 Jan 2011 02:23:14 +0000","from_user":"dbph","id_str":"30088341030440960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @dnene: Skilled Calisthenics. Haskell code that outputs python which spits ruby which emits the haskell source. http://j.mp/YlQUL via @mfeathers","id":30088341030440960,"from_user_id":24538048,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:58:31 +0000","from_user":"YubaVetTech","id_str":"30082124207886336","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigious Hayward Award for \u2018Excellence in Education\u2019. This award honors... http://fb.me/QgQCxd74","id":30082124207886336,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:56:04 +0000","from_user":"YubaVetTech","id_str":"30081505476743168","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigous Haward Award for Excellence in Education. This award honors... http://fb.me/PC9mYmCR","id":30081505476743168,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:43:50 +0000","from_user":"Verus","id_str":"30078427155406848","metadata":{"result_type":"recent"},"to_user_id":79273052,"text":"@kami_joe \u3044\u3084\uff0c\u8ab2\u984c\u306f\u89e3\u6c7a\u5bfe\u8c61(\u30d1\u30ba\u30eb\u3068\u304b)\u3092\u4e0e\u3048\u3089\u308c\u3066\uff0c\u554f\u984c\u5b9a\u7fa9\u3068\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0(\u6307\u5b9a\u8a00\u8a9e\u306fC++\u3082\u3057\u304f\u306fJava)\u3068\u3044\u3046\u3044\u308f\u3070\u666e\u901a\u306a\u8ab2\u984c\u3067\u306f\u3042\u308b\u3093\u3060\u3051\u3069\uff0e\u95a2\u6570\u578b\u8a00\u8a9e\u306fHaskell\u306e\u6388\u696d\u304c\u307e\u305f\u5225\u306b\u3042\u308b\u306e\uff0e","id":30078427155406848,"from_user_id":2331498,"to_user":"kami_joe","geo":null,"iso_language_code":"ja","to_user_id_str":"79273052","source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"79151233","profile_image_url":"http://a2.twimg.com/a/1295051201/images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 01:40:37 +0000","from_user":"cz_newdrafts","id_str":"30077617361125376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell programming language http://bit.ly/gpPAwB","id":30077617361125376,"from_user_id":79151233,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://tommorris.org/" rel="nofollow">tommorris' hacksample</a>"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:57 +0000","from_user":"Verus","id_str":"30068139416879104","metadata":{"result_type":"recent"},"to_user_id":9252720,"text":"@shukukei Java\u3068C\u306f\u3042\u308b\u7a0b\u5ea6\u66f8\u3051\u3066\u3042\u305f\u308a\u307e\u3048\u306a\u3068\u3053\u308d\u304c\u3042\u308b\u304b\u3089\u306a\u30fc\uff0ePython\u306f\u500b\u4eba\u7684\u306b\u611f\u899a\u304c\u5408\u308f\u306a\u3044\uff0e\u611f\u899a\u306a\u306e\u3067\uff0c\u3082\u3046\u3069\u3046\u3057\u3088\u3046\u3082\u306a\u3044\uff57 \u3044\u307e\u306fScala\u3068Haskell\u3092\u3082\u3063\u3068\u6975\u3081\u305f\u3044\u3068\u3053\u308d\uff0e","id":30068139416879104,"from_user_id":2331498,"to_user":"shukukei","geo":null,"iso_language_code":"ja","to_user_id_str":"9252720","source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"2781460","profile_image_url":"http://a0.twimg.com/profile_images/82526625/.joeyicon_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:35 +0000","from_user":"joeyhess","id_str":"30068046538219520","metadata":{"result_type":"recent"},"to_user_id":null,"text":"just figured out that I can use parameterized types to remove a dependency loop in git-annex's type definitions. whee #haskell","id":30068046538219520,"from_user_id":2781460,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://identi.ca" rel="nofollow">identica</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 00:54:22 +0000","from_user":"listwarenet","id_str":"30065977920061440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84466-haskell-beginners-bytestring-question.html Haskell-beginners - Bytestrin","id":30065977920061440,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"1291845","profile_image_url":"http://a0.twimg.com/profile_images/1225743404/ThinOxygen-small-opaque-solidarity_normal.png","created_at":"Wed, 26 Jan 2011 00:52:07 +0000","from_user":"_aaron_","id_str":"30065412242669568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"wanted: librly licensed high level native compiled lang with min runtime (otherwise cobra/mono would be perfect) for win. lua? haskell? ooc?","id":30065412242669568,"from_user_id":1291845,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"5912444","profile_image_url":"http://a2.twimg.com/profile_images/546261026/ssf0xg11_normal.jpg","created_at":"Wed, 26 Jan 2011 00:45:45 +0000","from_user":"shelarcy","id_str":"30063810773516288","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @Hackage: download 0.3.1.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/eHfiJB","id":30063810773516288,"from_user_id":5912444,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"135993","profile_image_url":"http://a2.twimg.com/profile_images/1190667086/myface2010small_normal.jpg","created_at":"Wed, 26 Jan 2011 00:41:00 +0000","from_user":"kudzu_naoki","id_str":"30062613287141376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u9b54\u6cd5Haskell\u5c11\u5973\u5019\u88dc\u3092\u63a2\u3059\u306e\u3082\u5927\u5909\u306a\u3093\u3060","id":30062613287141376,"from_user_id":135993,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"52620546","profile_image_url":"http://a1.twimg.com/profile_images/434693356/twitter-icon_normal.png","created_at":"Wed, 26 Jan 2011 00:40:25 +0000","from_user":"omasanori","id_str":"30062465656033280","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u9b54\u6cd5Haskell\u5c11\u5973\u306e\u4e00\u65e5\u306fGHC HEAD\u306e\u30d3\u30eb\u30c9\u304b\u3089\u59cb\u307e\u308b","id":30062465656033280,"from_user_id":52620546,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.movatwi.jp" rel="nofollow">www.movatwi.jp</a>"},{"from_user_id_str":"52620546","profile_image_url":"http://a1.twimg.com/profile_images/434693356/twitter-icon_normal.png","created_at":"Wed, 26 Jan 2011 00:37:12 +0000","from_user":"omasanori","id_str":"30061656331526144","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u50d5\u3068\u5951\u7d04\u3057\u3066\u9b54\u6cd5Haskell\u5c11\u5973\u306b\u306a\u308d\u3046\u3088\uff01","id":30061656331526144,"from_user_id":52620546,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"135993","profile_image_url":"http://a2.twimg.com/profile_images/1190667086/myface2010small_normal.jpg","created_at":"Wed, 26 Jan 2011 00:35:42 +0000","from_user":"kudzu_naoki","id_str":"30061282665168896","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u50d5\u3068\u5951\u7d04\u3057\u3066\u9b54\u6cd5Haskell\u5c11\u5973\u306b\u306a\u308d\u3046\u3088\uff01","id":30061282665168896,"from_user_id":135993,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"1631333","profile_image_url":"http://a1.twimg.com/profile_images/81268862/profile300_normal.jpg","created_at":"Wed, 26 Jan 2011 00:30:02 +0000","from_user":"qnighy","id_str":"30059855884582913","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u50d5\u3068\u5951\u7d04\u3057\u3066\u9b54\u6cd5Haskell\u5c11\u5973\u306b\u306a\u308d\u3046\u3088\uff01","id":30059855884582913,"from_user_id":1631333,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"9093754","profile_image_url":"http://a1.twimg.com/profile_images/99435906/PHD_3d_col_blk_normal.jpg","created_at":"Wed, 26 Jan 2011 00:26:20 +0000","from_user":"phdwine","id_str":"30058925516656640","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Last weekend of Tri Nations Tasting with PHD wines at Haskell Vineyards. Hope you didn't miss the Pinot Noir tasting last week !","id":30058925516656640,"from_user_id":9093754,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"2119923","profile_image_url":"http://a2.twimg.com/profile_images/1096701078/djayprofile_normal.jpg","created_at":"Wed, 26 Jan 2011 00:21:14 +0000","from_user":"djay75","id_str":"30057639543050240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @dnene: Skilled Calisthenics. Haskell code that outputs python which spits ruby which emits the haskell source. http://j.mp/YlQUL via @mfeathers","id":30057639543050240,"from_user_id":2119923,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"134323731","profile_image_url":"http://a2.twimg.com/profile_images/1225818824/IMG00518-20110125-1547_normal.jpg","created_at":"Wed, 26 Jan 2011 00:19:30 +0000","from_user":"PrinceOfBrkeley","id_str":"30057205554216960","metadata":{"result_type":"recent"},"to_user_id":167093027,"text":"@PayThaPrince go to haskell.","id":30057205554216960,"from_user_id":134323731,"to_user":"PayThaPrince","geo":null,"iso_language_code":"en","to_user_id_str":"167093027","source":"<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry\u00ae</a>"},{"from_user_id_str":"705857","profile_image_url":"http://a1.twimg.com/profile_images/429483912/ben_twitter_normal.jpg","created_at":"Wed, 26 Jan 2011 00:03:28 +0000","from_user":"bennadel","id_str":"30053166972141569","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Using #Homebrew to install Haskell - the last of the Seven Languages (in Seven Weeks) http://bit.ly/eA9Cv1 This has been some journey.","id":30053166972141569,"from_user_id":705857,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"251466","profile_image_url":"http://a2.twimg.com/profile_images/1194100934/pass_normal.jpg","created_at":"Wed, 26 Jan 2011 00:02:54 +0000","from_user":"simonszu","id_str":"30053025502466048","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Ouh yeah! Ich werde doch produktiv sein, diese Semesterferien. Ich werde funktional Programmieren lernen. #haskell, Baby.","id":30053025502466048,"from_user_id":251466,"geo":null,"iso_language_code":"de","to_user_id_str":null,"source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"357786","profile_image_url":"http://a0.twimg.com/profile_images/612044841/FM_2010_normal.jpg","created_at":"Tue, 25 Jan 2011 23:59:13 +0000","from_user":"diligiant","id_str":"30052100973006848","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @paulrbrown: "...we only discovered a single bug after compilation." (http://t.co/K0wlEYz) #haskell","id":30052100973006848,"from_user_id":357786,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"101597523","profile_image_url":"http://a1.twimg.com/profile_images/1206183256/2010-12-12-204902_normal.jpg","created_at":"Tue, 25 Jan 2011 23:54:46 +0000","from_user":"wlad_kent","id_str":"30050977964892160","metadata":{"result_type":"recent"},"to_user_id":86297184,"text":"@Nilson_Neto Isso eh bem basico. quando vc estiver estudando recurs\u00e3o em Haskell, ai vc vai ver oq eh papo de nerd - kkk - 1\u00ba periodo isso.","id":30050977964892160,"from_user_id":101597523,"to_user":"Nilson_Neto","geo":null,"iso_language_code":"pt","to_user_id_str":"86297184","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Tue, 25 Jan 2011 23:51:22 +0000","from_user":"listwarenet","id_str":"30050123383832577","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84336-haskell-cafe-monomorphic-let-bindings-and-darcs.html Haskell-cafe - Monomorph","id":30050123383832577,"from_user_id":144546280,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"5776901","profile_image_url":"http://a0.twimg.com/profile_images/472682157/lucabw_normal.JPG","created_at":"Tue, 25 Jan 2011 23:48:40 +0000","from_user":"lsbardel","id_str":"30049446469312512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Very interesting technology stack these guys use http://bit.ly/ghAjS7 #python #redis #haskell","id":30049446469312512,"from_user_id":5776901,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"3005901","profile_image_url":"http://a0.twimg.com/profile_images/278943006/Lone_Pine_Peak_-_Peter_200x200_normal.jpg","created_at":"Tue, 25 Jan 2011 23:45:48 +0000","from_user":"pmonks","id_str":"30048721110573056","metadata":{"result_type":"recent"},"to_user_id":203834278,"text":"@techielicous Haskell: http://bit.ly/gy3oFi ;-)","id":30048721110573056,"from_user_id":3005901,"to_user":"techielicous","geo":null,"iso_language_code":"en","to_user_id_str":"203834278","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"162697074","profile_image_url":"http://a2.twimg.com/profile_images/826205838/ryan3_normal.jpg","created_at":"Tue, 25 Jan 2011 23:44:47 +0000","from_user":"TheRonaldMCD","id_str":"30048468781244416","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Aldi Food Market (4122 Gaston Ave, Haskell, Dallas) http://4sq.com/ekqRY7","id":30048468781244416,"from_user_id":162697074,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"203834278","profile_image_url":"http://a0.twimg.com/profile_images/1223375080/me_normal.jpg","created_at":"Tue, 25 Jan 2011 23:44:04 +0000","from_user":"techielicous","id_str":"30048286589067264","metadata":{"result_type":"recent"},"to_user_id":3005901,"text":"@pmonks I was thinking Haskell or Scheme","id":30048286589067264,"from_user_id":203834278,"to_user":"pmonks","geo":null,"iso_language_code":"en","to_user_id_str":"3005901","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"537690","profile_image_url":"http://a3.twimg.com/profile_images/45665122/nushiostamp_normal.jpg","created_at":"Tue, 25 Jan 2011 23:38:14 +0000","from_user":"nushio","id_str":"30046818658164737","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u305d\u3046\u3044\u3084\u5951\u7d04\u306b\u3088\u308b\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u3068\u304b\u3042\u3063\u305f\u306a\u3002Haskell\u306a\u3093\u304b\u3088\u308a\u3042\u3063\u3061\u306e\u65b9\u304c\u9b54\u6cd5\u5c11\u5973\u547c\u3070\u308f\u308a\u306b\u3075\u3055\u308f\u3057\u3044\u3002","id":30046818658164737,"from_user_id":537690,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"181192","profile_image_url":"http://a2.twimg.com/profile_images/1089890701/q530888600_9828_normal.jpg","created_at":"Tue, 25 Jan 2011 23:38:03 +0000","from_user":"aodag","id_str":"30046772223016960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @omasanori: \u300c\u3082\u3046\u4f55\u5e74\u3082Haskell\u306e\u3053\u3068\u3057\u304b\u8003\u3048\u3066\u306a\u304b\u3063\u305f\u304b\u3089\u306a\u3001\u30eb\u30fc\u30d7\u306e\u4f7f\u3044\u65b9\u5fd8\u308c\u3066\u305f\u300d","id":30046772223016960,"from_user_id":181192,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.movatwi.jp" rel="nofollow">www.movatwi.jp</a>"},{"from_user_id_str":"5886055","profile_image_url":"http://a3.twimg.com/profile_images/85531669/ichi_normal.jpg","created_at":"Tue, 25 Jan 2011 23:37:53 +0000","from_user":"kanaya","id_str":"30046729243983873","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u9e97\u3057\u3044\u3002\u201c@omasanori: \u300c\u3082\u3046\u4f55\u5e74\u3082Haskell\u306e\u3053\u3068\u3057\u304b\u8003\u3048\u3066\u306a\u304b\u3063\u305f\u304b\u3089\u306a\u3001\u30eb\u30fc\u30d7\u306e\u4f7f\u3044\u65b9\u5fd8\u308c\u3066\u305f\u300d\u201d","id":30046729243983873,"from_user_id":5886055,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/app/twitter/id333903271?mt=8" rel="nofollow">Twitter for iPad</a>"},{"from_user_id_str":"52620546","profile_image_url":"http://a1.twimg.com/profile_images/434693356/twitter-icon_normal.png","created_at":"Tue, 25 Jan 2011 23:36:26 +0000","from_user":"omasanori","id_str":"30046367187476481","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u300c\u3082\u3046\u4f55\u5e74\u3082Haskell\u306e\u3053\u3068\u3057\u304b\u8003\u3048\u3066\u306a\u304b\u3063\u305f\u304b\u3089\u306a\u3001\u30eb\u30fc\u30d7\u306e\u4f7f\u3044\u65b9\u5fd8\u308c\u3066\u305f\u300d","id":30046367187476481,"from_user_id":52620546,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.movatwi.jp" rel="nofollow">www.movatwi.jp</a>"},{"from_user_id_str":"1659992","profile_image_url":"http://a1.twimg.com/profile_images/504488750/1_normal.jpg","created_at":"Tue, 25 Jan 2011 23:16:13 +0000","from_user":"finalfusion","id_str":"30041278544609280","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @necocen: Haskell\u306e\u30df\u30b5\u30ef\u3001\u3068\u3044\u3046\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u3066\u3071\u3063\u3068\u3057\u306a\u3044","id":30041278544609280,"from_user_id":1659992,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"272513","profile_image_url":"http://a2.twimg.com/profile_images/320244078/Mike_Painting2_normal.png","created_at":"Tue, 25 Jan 2011 23:05:09 +0000","from_user":"mikehadlow","id_str":"30038492373319680","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Just written the same simple program in C#, F# and Haskell: 18, 12 and 9 LoC respectively. And I'm much better at C# than F# or Haskell.","id":30038492373319680,"from_user_id":272513,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"89393264","profile_image_url":"http://a0.twimg.com/profile_images/1169486472/020_portland_me_normal.jpg","created_at":"Tue, 25 Jan 2011 23:01:28 +0000","from_user":"newsportlandme","id_str":"30037564589084673","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Governor's Choice to Run Maine DOC Under Scrutiny - MPBN: State Rep. Anne Haskell, a Portland Democrat, says Mai... http://bit.ly/fO30gC","id":30037564589084673,"from_user_id":89393264,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"38138","profile_image_url":"http://a3.twimg.com/profile_images/1212565885/Screen_shot_2011-01-11_at_5.28.47_PM_normal.png","created_at":"Tue, 25 Jan 2011 22:59:55 +0000","from_user":"michaelneale","id_str":"30037174615281664","metadata":{"result_type":"recent"},"to_user_id":null,"text":"The haskell EvilMangler http://t.co/P2Tls7J","id":30037174615281664,"from_user_id":38138,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"45692","profile_image_url":"http://a3.twimg.com/profile_images/1177741507/dogkarno_r_normal.jpg","created_at":"Tue, 25 Jan 2011 22:45:06 +0000","from_user":"karno","id_str":"30033448286552064","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u3063\u3066\u95a2\u6570\u306b\u30ab\u30ec\u30fc\u7c89\u3076\u3061\u8fbc\u3080\u3068\u304b\u306a\u3093\u3068\u304b","id":30033448286552064,"from_user_id":45692,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://yubitter.com/" rel="nofollow">yubitter</a>"},{"from_user_id_str":"27605","profile_image_url":"http://a2.twimg.com/profile_images/15826632/meron_normal.jpg","created_at":"Tue, 25 Jan 2011 22:44:23 +0000","from_user":"celeron1ghz","id_str":"30033268761956352","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @necocen: Haskell\u306e\u30df\u30b5\u30ef\u3001\u3068\u3044\u3046\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u3066\u3071\u3063\u3068\u3057\u306a\u3044","id":30033268761956352,"from_user_id":27605,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"12901","profile_image_url":"http://a1.twimg.com/profile_images/56091349/haruhi_nagato-Y_normal.jpg","created_at":"Tue, 25 Jan 2011 22:43:30 +0000","from_user":"necocen","id_str":"30033044035346432","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u307e\u3042Haskell\u77e5\u3089\u3093\u3057\u306d","id":30033044035346432,"from_user_id":12901,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"12901","profile_image_url":"http://a1.twimg.com/profile_images/56091349/haruhi_nagato-Y_normal.jpg","created_at":"Tue, 25 Jan 2011 22:42:54 +0000","from_user":"necocen","id_str":"30032894856531968","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u306e\u30df\u30b5\u30ef\u3001\u3068\u3044\u3046\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u3066\u3071\u3063\u3068\u3057\u306a\u3044","id":30032894856531968,"from_user_id":12901,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"10821270","profile_image_url":"http://a0.twimg.com/profile_images/1195474259/Salto_Marlon_normal.jpg","created_at":"Tue, 25 Jan 2011 22:35:09 +0000","from_user":"jjedMoriAnktah","id_str":"30030942106025984","metadata":{"result_type":"recent"},"to_user_id":null,"text":""A Haskell program that outputs a Python program that outputs a Ruby program that outputs the original Haskell program" http://is.gd/E6Julu","id":30030942106025984,"from_user_id":10821270,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"7554762","profile_image_url":"http://a0.twimg.com/profile_images/100515212/ajay-photo_normal.jpg","created_at":"Tue, 25 Jan 2011 22:34:30 +0000","from_user":"comatose_kid","id_str":"30030780205899776","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @bumptech: Bump Dev Blog - Why we use Haskell at Bump http://devblog.bu.mp/haskell-at-bump","id":30030780205899776,"from_user_id":7554762,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"148474705","profile_image_url":"http://a0.twimg.com/profile_images/1119234716/fur_hat_-_gilbeys_vodka_-_life_-_11-30-1962_normal.JPG","created_at":"Tue, 25 Jan 2011 22:29:19 +0000","from_user":"landmvintage","id_str":"30029476003840000","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @faerymoongodess: Magnificent Miriam Haskell Baroque Pearl Necklace by @MercyMadge http://etsy.me/hqRl51","id":30029476003840000,"from_user_id":148474705,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"37715508","profile_image_url":"http://a1.twimg.com/profile_images/1207891411/ballerina_normal.jpg","created_at":"Tue, 25 Jan 2011 22:24:52 +0000","from_user":"faerymoongodess","id_str":"30028356326002688","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Magnificent Miriam Haskell Baroque Pearl Necklace by @MercyMadge http://etsy.me/hqRl51","id":30028356326002688,"from_user_id":37715508,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Tue, 25 Jan 2011 22:17:16 +0000","from_user":"Hackage","id_str":"30026442456694784","metadata":{"result_type":"recent"},"to_user_id":null,"text":"base16-bytestring 0.1.0.0, added by BryanOSullivan: Fast base16 (hex) encoding and deconding for ByteStrings http://bit.ly/eu75TN","id":30026442456694784,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"199750997","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Tue, 25 Jan 2011 22:12:07 +0000","from_user":"benreads","id_str":"30025146991382528","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Writing Systems Software in a Functional Language -- brief, but fun. I want to see how well they can make Systems Haskell perform at scale.","id":30025146991382528,"from_user_id":199750997,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"35359797","profile_image_url":"http://a1.twimg.com/profile_images/1173453785/48893_521140819_1896062_q_normal.jpg","created_at":"Tue, 25 Jan 2011 22:09:45 +0000","from_user":"jcawthorne1","id_str":"30024549265309696","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Just saw Jeff Haskell give the middle finger!! Lol awesome","id":30024549265309696,"from_user_id":35359797,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Tue, 25 Jan 2011 22:06:44 +0000","from_user":"goodfox","id_str":"30023790381498369","metadata":{"result_type":"recent"},"to_user_id":null,"text":"At the Haskell Convocation. (@ Haskell Indian Nations U Auditorium) http://4sq.com/eKKXyn","id":30023790381498369,"from_user_id":13540930,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"14674418","profile_image_url":"http://a2.twimg.com/profile_images/238230125/IMG_1030-1_normal.jpg","created_at":"Tue, 25 Jan 2011 22:02:31 +0000","from_user":"sanityinc","id_str":"30022731919523840","metadata":{"result_type":"recent"},"to_user_id":371289,"text":"@xshay Haskell's great, but Clojure's similarly lazy in all the ways that matter, and is more practical for day-to-day use.","id":30022731919523840,"from_user_id":14674418,"to_user":"xshay","geo":null,"iso_language_code":"en","to_user_id_str":"371289","source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"371289","profile_image_url":"http://a2.twimg.com/profile_images/1113482439/me-brisbane_normal.jpg","created_at":"Tue, 25 Jan 2011 21:58:29 +0000","from_user":"xshay","id_str":"30021714444292096","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Just made a lazy sequence of prime numbers in haskell. I'm smitten.","id":30021714444292096,"from_user_id":371289,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"199453873","profile_image_url":"http://a3.twimg.com/a/1294785484/images/default_profile_3_normal.png","created_at":"Tue, 25 Jan 2011 21:48:40 +0000","from_user":"stackfeed","id_str":"30019243982454784","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Practical Scala reference manual, for searching things like method names: Hello, \n\nInspired by\nHaskell API Searc... http://bit.ly/g4zWZQ","id":30019243982454784,"from_user_id":199453873,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Tue, 25 Jan 2011 21:45:32 +0000","from_user":"aapnoot","id_str":"30018455189065728","metadata":{"result_type":"recent"},"to_user_id":null,"text":"download 0.3.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/i8mYvi","id":30018455189065728,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Tue, 25 Jan 2011 21:45:31 +0000","from_user":"aapnoot","id_str":"30018452601180160","metadata":{"result_type":"recent"},"to_user_id":null,"text":"download 0.3.1.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/eHfiJB","id":30018452601180160,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Tue, 25 Jan 2011 21:45:31 +0000","from_user":"Hackage","id_str":"30018451867176960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"download 0.3.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/i8mYvi","id":30018451867176960,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"138502705","profile_image_url":"http://a1.twimg.com/profile_images/1083845614/yclogo_normal.gif","created_at":"Tue, 25 Jan 2011 21:45:04 +0000","from_user":"newsyc100","id_str":"30018340839755777","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell improves log processing 4x over Python http://devblog.bu.mp/haskell-at-bump (http://bit.ly/gQxxR8)","id":30018340839755777,"from_user_id":138502705,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://news.ycombinator.com" rel="nofollow">newsyc</a>"},{"from_user_id_str":"1578246","profile_image_url":"http://a0.twimg.com/profile_images/59312315/avatar_simpson_small_normal.jpg","created_at":"Tue, 25 Jan 2011 21:43:32 +0000","from_user":"magthe","id_str":"30017953801969665","metadata":{"result_type":"recent"},"to_user_id":null,"text":"New version of download uploaded to #hackage #haskell","id":30017953801969665,"from_user_id":1578246,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://api.supertweet.net" rel="nofollow">MyAuth API Proxy</a>"},{"from_user_id_str":"135838970","profile_image_url":"http://a2.twimg.com/profile_images/1079929891/logo_normal.png","created_at":"Tue, 25 Jan 2011 21:37:51 +0000","from_user":"reward999","id_str":"30016525180084224","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Found Great Dane (Main & Haskell- Dallas): We found a great dane. 214-712-0000 http://bit.ly/fQ8iBw","id":30016525180084224,"from_user_id":135838970,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"137719265","profile_image_url":"http://a2.twimg.com/profile_images/1092224079/8__4__normal.jpg","created_at":"Tue, 25 Jan 2011 21:34:22 +0000","from_user":"WeiMatas","id_str":"30015646020411392","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Fourth day Rez party Eddie Haskell County in second life \u2013 which took place in cabaret Tadd","id":30015646020411392,"from_user_id":137719265,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://dlvr.it" rel="nofollow">dlvr.it</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Tue, 25 Jan 2011 21:33:21 +0000","from_user":"listwarenet","id_str":"30015392571195392","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/83889-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Haskell-cafe -","id":30015392571195392,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"}],"max_id":30121530767708160,"since_id":0,"refresh_url":"?since_id=30121530767708160&q=haskell","next_page":"?page=2&max_id=30121530767708160&rpp=100&q=haskell","results_per_page":100,"page":1,"completed_in":1.195569,"since_id_str":"0","max_id_str":"30121530767708160","query":"haskell"}+{"results":[{"from_user_id_str":"3646730","profile_image_url":"http://a3.twimg.com/profile_images/404973767/avatar_normal.jpg","created_at":"Wed, 26 Jan 2011 04:35:07 +0000","from_user":"nicolaslara","id_str":"30121530767708160","metadata":{"result_type":"recent"},"to_user_id":18616016,"text":"@josej30 Python y Clojure. Obviamente son diferentes, y cada uno tiene sus ventajas y desventajas. De Haskell faltar\u00eda pattern matching","id":30121530767708160,"from_user_id":3646730,"to_user":"josej30","geo":null,"iso_language_code":"es","to_user_id_str":"18616016","source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"207858021","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 04:30:38 +0000","from_user":"pboudarga","id_str":"30120402839666689","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Rolla Sushi Grill (27737 Bouquet Canyon Road, #106, Btw Haskell Canyon and Rosedell Drive, Saugus) http://4sq.com/gqqdhs","id":30120402839666689,"from_user_id":207858021,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"69988683","profile_image_url":"http://a0.twimg.com/profile_images/1211955817/avatar_7888_normal.gif","created_at":"Wed, 26 Jan 2011 04:25:23 +0000","from_user":"YNK33","id_str":"30119083059978240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"hsndfile 0.5.0: Free and open source Haskell bindings for libsndfile http://bit.ly/gHaBWG Mac Os","id":30119083059978240,"from_user_id":69988683,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"81492","profile_image_url":"http://a1.twimg.com/profile_images/423894208/Picture_7_normal.jpg","created_at":"Wed, 26 Jan 2011 04:24:28 +0000","from_user":"satzz","id_str":"30118851488251904","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Emacs\u306e\u30e2\u30fc\u30c9\u8868\u793a\u304c\u4eca(Ruby Controller Outputz RoR Flymake REl hs)\u3068\u306a\u3063\u3066\u3066\u3088\u304f\u308f\u304b\u3089\u306a\u3044\u3093\u3060\u3051\u3069\u6700\u5f8c\u306eREl\u3068\u304bhs\u3063\u3066\u4f55\u3060\u308d\u3046\u2026haskell\u3068\u304b2\u5e74\u4ee5\u4e0a\u66f8\u3044\u3066\u306a\u3044\u3051\u3069\u2026","id":30118851488251904,"from_user_id":81492,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"9518356","profile_image_url":"http://a2.twimg.com/profile_images/119165723/ocaml-icon_normal.png","created_at":"Wed, 26 Jan 2011 04:19:19 +0000","from_user":"planet_ocaml","id_str":"30117557788741632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I so miss #haskell type classes in #ocaml - i want to do something like refinement. Also why does ocaml not have... http://bit.ly/geYRwt","id":30117557788741632,"from_user_id":9518356,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"218059","profile_image_url":"http://a1.twimg.com/profile_images/1053837723/twitter-icon9_normal.jpg","created_at":"Wed, 26 Jan 2011 04:16:32 +0000","from_user":"aprikip","id_str":"30116854940835840","metadata":{"result_type":"recent"},"to_user_id":null,"text":"yatex-mode\u3084haskell-mode\u306e\u3053\u3068\u3067\u3059\u306d\u3001\u308f\u304b\u308a\u307e\u3059\u3002","id":30116854940835840,"from_user_id":218059,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sites.google.com/site/yorufukurou/" rel="nofollow">YoruFukurou</a>"},{"from_user_id_str":"216363","profile_image_url":"http://a1.twimg.com/profile_images/72454310/Tim-Avatar_normal.png","created_at":"Wed, 26 Jan 2011 04:15:30 +0000","from_user":"dysinger","id_str":"30116594684264448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell in Hawaii tonight for me... #fun","id":30116594684264448,"from_user_id":216363,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.nambu.com/" rel="nofollow">Nambu</a>"},{"from_user_id_str":"1774820","profile_image_url":"http://a2.twimg.com/profile_images/61169291/dan_desert_thumb_normal.jpg","created_at":"Wed, 26 Jan 2011 04:13:36 +0000","from_user":"DanMil","id_str":"30116117682851840","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire @tomheon Haskell isn't a language, it's a belief system. A seductive one...","id":30116117682851840,"from_user_id":1774820,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"659256","profile_image_url":"http://a0.twimg.com/profile_images/746976711/angular-final_normal.jpg","created_at":"Wed, 26 Jan 2011 04:11:06 +0000","from_user":"djspiewak","id_str":"30115488931520512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"One of the very nice things about Haskell as opposed to SML is the reduced proliferation of identifiers (e.g. andb, orb, etc). #typeclasses","id":30115488931520512,"from_user_id":659256,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 04:06:12 +0000","from_user":"listwarenet","id_str":"30114255890026496","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84752-re-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Re: Haskell-c","id":30114255890026496,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 04:01:29 +0000","from_user":"ojrac","id_str":"30113067333324800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tomheon: @ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30113067333324800,"from_user_id":1594784,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"207589736","profile_image_url":"http://a3.twimg.com/profile_images/1225527428/headshot_1_normal.jpg","created_at":"Wed, 26 Jan 2011 04:00:13 +0000","from_user":"ashleevelazq101","id_str":"30112747555397632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/dONnpn","id":30112747555397632,"from_user_id":207589736,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"Hackage","id_str":"30112192346984448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112192346984448,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"aapnoot","id_str":"30112191881420800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112191881420800,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"8530482","profile_image_url":"http://a2.twimg.com/profile_images/137867266/n608671563_7396_normal.jpg","created_at":"Wed, 26 Jan 2011 03:50:12 +0000","from_user":"jeffmclamb","id_str":"30110229207187456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Angel - daemon to run and monitor processes like daemontools or god, written in Haskell http://ff.im/-wNyLk","id":30110229207187456,"from_user_id":8530482,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://friendfeed.com" rel="nofollow">FriendFeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:46:01 +0000","from_user":"tomheon","id_str":"30109174645919744","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30109174645919744,"from_user_id":177539201,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 03:44:34 +0000","from_user":"ojrac","id_str":"30108808684503040","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire @tomheon Why are you making me curious about Haskell? I LIKE not knowing what monad means!!","id":30108808684503040,"from_user_id":1594784,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"23750094","profile_image_url":"http://a0.twimg.com/profile_images/951373780/Moeinthecar_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:54 +0000","from_user":"shokalshab","id_str":"30108140443795456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Magnitude Cheer @ Gymnastics Olympica USA (7735 Haskell Ave., btw Saticoy & Strathern, Van Nuys) http://4sq.com/gmXfaL","id":30108140443795456,"from_user_id":23750094,"geo":null,"iso_language_code":"en","place":{"id":"4e4a2a2f86cb2946","type_":"poi","full_name":"Gymnastics Olympica USA, Van Nuys"},"to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"8135112","profile_image_url":"http://a0.twimg.com/profile_images/1165240350/LIMITED_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:35 +0000","from_user":"Claricei","id_str":"30108059208515584","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @kristenmchugh22: @KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30108059208515584,"from_user_id":8135112,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:40:02 +0000","from_user":"chewedwire","id_str":"30107670367182848","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon Cool, I'll take a look. I feel like I should mention this: http://bit.ly/hVstDM","id":30107670367182848,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"8679778","profile_image_url":"http://a3.twimg.com/profile_images/1195318056/me_nyc_12_18_10_icon_normal.jpg","created_at":"Wed, 26 Jan 2011 03:38:42 +0000","from_user":"kristenmchugh22","id_str":"30107332381777920","metadata":{"result_type":"recent"},"to_user_id":756269,"text":"@KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30107332381777920,"from_user_id":8679778,"to_user":"KeithOlbermann","geo":null,"iso_language_code":"en","to_user_id_str":"756269","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"103316559","profile_image_url":"http://a1.twimg.com/profile_images/1179458751/bc3beab4-d59d-4e78-b13b-50747986cfa2_normal.png","created_at":"Wed, 26 Jan 2011 03:36:15 +0000","from_user":"cityslikr","id_str":"30106719153557504","metadata":{"result_type":"recent"},"to_user_id":null,"text":""Social safety net into a hammock." So says Eddie Haskell with the GOP response. #SOTU","id":30106719153557504,"from_user_id":103316559,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry\u00ae</a>"},{"from_user_id_str":"169063143","profile_image_url":"http://a0.twimg.com/profile_images/1160506212/9697_1_normal.gif","created_at":"Wed, 26 Jan 2011 03:31:52 +0000","from_user":"wrkforce_safety","id_str":"30105614919143424","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/gA60C1","id":30105614919143424,"from_user_id":169063143,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:29:40 +0000","from_user":"tomheon","id_str":"30105060960632832","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire Great book on Haskell: http://oreilly.com/catalog/9780596514983","id":30105060960632832,"from_user_id":177539201,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"782692","profile_image_url":"http://a0.twimg.com/profile_images/1031304589/Profile.2007.1_normal.jpg","created_at":"Wed, 26 Jan 2011 03:29:19 +0000","from_user":"turnageb","id_str":"30104974591533057","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @ovillalon: Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104974591533057,"from_user_id":782692,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:28:04 +0000","from_user":"chewedwire","id_str":"30104657267265536","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon I always loved the pattern matching in SML and it looks like Haskell is MUCH better at it. I'm messing around now at tryhaskell.org","id":30104657267265536,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"12834082","profile_image_url":"http://a3.twimg.com/profile_images/1083036140/mugshot_normal.png","created_at":"Wed, 26 Jan 2011 03:28:01 +0000","from_user":"ovillalon","id_str":"30104647213518848","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104647213518848,"from_user_id":12834082,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:26:02 +0000","from_user":"goodfox","id_str":"30104146455560192","metadata":{"result_type":"recent"},"to_user_id":10226179,"text":"@billykeene22 Bordeaux is one of my heroes. I was so excited when he accepted the invitation to campus. He's been a great friend to Haskell.","id":30104146455560192,"from_user_id":13540930,"to_user":"billykeene22","geo":null,"iso_language_code":"en","to_user_id_str":"10226179","source":"<a href="http://www.ubertwitter.com/bb/download.php" rel="nofollow">\u00dcberTwitter</a>"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 03:25:18 +0000","from_user":"josej30","id_str":"30103962313031681","metadata":{"result_type":"recent"},"to_user_id":14870909,"text":"@cris7ian Ahh bueno multiparadigma ya es respetable :) Empezar\u00e9 a explotar la parte funcional de los lenguajes ahora #Haskell","id":30103962313031681,"from_user_id":18616016,"to_user":"Cris7ian","geo":null,"iso_language_code":"es","to_user_id_str":"14870909","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"14870909","profile_image_url":"http://a2.twimg.com/profile_images/1176930429/oso_yo_normal.png","created_at":"Wed, 26 Jan 2011 03:23:43 +0000","from_user":"Cris7ian","id_str":"30103562360983553","metadata":{"result_type":"recent"},"to_user_id":18616016,"text":"@josej30 hahaha no, es multiparadigma y es bastante lazy. Nothing like haskell, pero s\u00ed, el de Flash","id":30103562360983553,"from_user_id":14870909,"to_user":"josej30","geo":null,"iso_language_code":"es","to_user_id_str":"18616016","source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"2421643","profile_image_url":"http://a0.twimg.com/profile_images/1190361665/ernestgrumbles-17_normal.jpg","created_at":"Wed, 26 Jan 2011 03:20:24 +0000","from_user":"ernestgrumbles","id_str":"30102730756333568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Wow... WolframAlpha did not know who Eddie Haskell is. Guess I'll never use that "knowledge engine" again.","id":30102730756333568,"from_user_id":2421643,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:14:21 +0000","from_user":"chewedwire","id_str":"30101204428132352","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon How is Haskell better/different from CL or Scheme? I honestly don't know, although I'm becoming more curious.","id":30101204428132352,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:06:54 +0000","from_user":"goodfox","id_str":"30099329809129473","metadata":{"result_type":"recent"},"to_user_id":null,"text":"A day of vision & speeches. #SOTU now. And a wonderful Haskell Convocation address earlier today by Sinte Gleske President Lionel Bordeaux.","id":30099329809129473,"from_user_id":13540930,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.ubertwitter.com/bb/download.php" rel="nofollow">\u00dcberTwitter</a>"},{"from_user_id_str":"119185220","profile_image_url":"http://a0.twimg.com/profile_images/1089027228/dfg_normal.jpg","created_at":"Wed, 26 Jan 2011 03:03:38 +0000","from_user":"LaLiciouz_03","id_str":"30098510623805440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"The Game with the girl room 330 Haskell follow us...","id":30098510623805440,"from_user_id":119185220,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 02:57:25 +0000","from_user":"josej30","id_str":"30096946144215040","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Voy a extra\u00f1ar Haskell cuando regrese al mundo imperativo. Hay alg\u00fan lenguaje imperativo que tenga este poder funcional? #ci3661","id":30096946144215040,"from_user_id":18616016,"geo":null,"iso_language_code":"es","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 02:55:32 +0000","from_user":"Hackage","id_str":"30096471814574080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"comonad-transformers 0.9.0, added by EdwardKmett: Haskell 98 comonad transformers http://bit.ly/h6xIsf","id":30096471814574080,"from_user_id":17671137,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 02:48:12 +0000","from_user":"tomheon","id_str":"30094626920603649","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Every time I look at Haskell I love it more.","id":30094626920603649,"from_user_id":177539201,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"60792568","profile_image_url":"http://a0.twimg.com/profile_images/1203647517/glenda-flash_normal.jpg","created_at":"Wed, 26 Jan 2011 02:40:42 +0000","from_user":"r_takaishi","id_str":"30092735935422464","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u3088\u308aD\u8a00\u8a9e\u304c\u4e0a\u3068\u306f\u601d\u308f\u306a\u304b\u3063\u305f\uff0e http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html","id":30092735935422464,"from_user_id":60792568,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twmode.sf.net/" rel="nofollow">twmode</a>"},{"from_user_id_str":"160145510","profile_image_url":"http://a0.twimg.com/profile_images/1218108166/going_galt_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:31 +0000","from_user":"wtp1787","id_str":"30092439653974018","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @KLSouth: Eddie Haskell Goes to Washington... "You look really nice tonight, Ms Cleaver"","id":30092439653974018,"from_user_id":160145510,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"96616016","profile_image_url":"http://a1.twimg.com/profile_images/1196978169/Picture0002_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:20 +0000","from_user":"MelissaRNMBA","id_str":"30092392203816960","metadata":{"result_type":"recent"},"to_user_id":14862975,"text":"@KLSouth At least Eddie Haskell was entertaining.","id":30092392203816960,"from_user_id":96616016,"to_user":"KLSouth","geo":null,"iso_language_code":"en","to_user_id_str":"14862975","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"14862975","profile_image_url":"http://a0.twimg.com/profile_images/421596393/kls_4_normal.JPG","created_at":"Wed, 26 Jan 2011 02:38:29 +0000","from_user":"KLSouth","id_str":"30092178327871489","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Eddie Haskell Goes to Washington... "You look really nice tonight, Ms Cleaver"","id":30092178327871489,"from_user_id":14862975,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 02:36:17 +0000","from_user":"listwarenet","id_str":"30091626869161984","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84641-haskell-beginners-wildcards-in-expressions.html Haskell-beginners - Wild","id":30091626869161984,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"24538048","profile_image_url":"http://a2.twimg.com/profile_images/1117267605/rope_normal.jpg","created_at":"Wed, 26 Jan 2011 02:23:14 +0000","from_user":"dbph","id_str":"30088341030440960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @dnene: Skilled Calisthenics. Haskell code that outputs python which spits ruby which emits the haskell source. http://j.mp/YlQUL via @mfeathers","id":30088341030440960,"from_user_id":24538048,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:58:31 +0000","from_user":"YubaVetTech","id_str":"30082124207886336","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigious Hayward Award for \u2018Excellence in Education\u2019. This award honors... http://fb.me/QgQCxd74","id":30082124207886336,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:56:04 +0000","from_user":"YubaVetTech","id_str":"30081505476743168","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigous Haward Award for Excellence in Education. This award honors... http://fb.me/PC9mYmCR","id":30081505476743168,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:43:50 +0000","from_user":"Verus","id_str":"30078427155406848","metadata":{"result_type":"recent"},"to_user_id":79273052,"text":"@kami_joe \u3044\u3084\uff0c\u8ab2\u984c\u306f\u89e3\u6c7a\u5bfe\u8c61(\u30d1\u30ba\u30eb\u3068\u304b)\u3092\u4e0e\u3048\u3089\u308c\u3066\uff0c\u554f\u984c\u5b9a\u7fa9\u3068\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0(\u6307\u5b9a\u8a00\u8a9e\u306fC++\u3082\u3057\u304f\u306fJava)\u3068\u3044\u3046\u3044\u308f\u3070\u666e\u901a\u306a\u8ab2\u984c\u3067\u306f\u3042\u308b\u3093\u3060\u3051\u3069\uff0e\u95a2\u6570\u578b\u8a00\u8a9e\u306fHaskell\u306e\u6388\u696d\u304c\u307e\u305f\u5225\u306b\u3042\u308b\u306e\uff0e","id":30078427155406848,"from_user_id":2331498,"to_user":"kami_joe","geo":null,"iso_language_code":"ja","to_user_id_str":"79273052","source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"79151233","profile_image_url":"http://a2.twimg.com/a/1295051201/images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 01:40:37 +0000","from_user":"cz_newdrafts","id_str":"30077617361125376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell programming language http://bit.ly/gpPAwB","id":30077617361125376,"from_user_id":79151233,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://tommorris.org/" rel="nofollow">tommorris' hacksample</a>"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:57 +0000","from_user":"Verus","id_str":"30068139416879104","metadata":{"result_type":"recent"},"to_user_id":9252720,"text":"@shukukei Java\u3068C\u306f\u3042\u308b\u7a0b\u5ea6\u66f8\u3051\u3066\u3042\u305f\u308a\u307e\u3048\u306a\u3068\u3053\u308d\u304c\u3042\u308b\u304b\u3089\u306a\u30fc\uff0ePython\u306f\u500b\u4eba\u7684\u306b\u611f\u899a\u304c\u5408\u308f\u306a\u3044\uff0e\u611f\u899a\u306a\u306e\u3067\uff0c\u3082\u3046\u3069\u3046\u3057\u3088\u3046\u3082\u306a\u3044\uff57 \u3044\u307e\u306fScala\u3068Haskell\u3092\u3082\u3063\u3068\u6975\u3081\u305f\u3044\u3068\u3053\u308d\uff0e","id":30068139416879104,"from_user_id":2331498,"to_user":"shukukei","geo":null,"iso_language_code":"ja","to_user_id_str":"9252720","source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"2781460","profile_image_url":"http://a0.twimg.com/profile_images/82526625/.joeyicon_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:35 +0000","from_user":"joeyhess","id_str":"30068046538219520","metadata":{"result_type":"recent"},"to_user_id":null,"text":"just figured out that I can use parameterized types to remove a dependency loop in git-annex's type definitions. whee #haskell","id":30068046538219520,"from_user_id":2781460,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://identi.ca" rel="nofollow">identica</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 00:54:22 +0000","from_user":"listwarenet","id_str":"30065977920061440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84466-haskell-beginners-bytestring-question.html Haskell-beginners - Bytestrin","id":30065977920061440,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"1291845","profile_image_url":"http://a0.twimg.com/profile_images/1225743404/ThinOxygen-small-opaque-solidarity_normal.png","created_at":"Wed, 26 Jan 2011 00:52:07 +0000","from_user":"_aaron_","id_str":"30065412242669568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"wanted: librly licensed high level native compiled lang with min runtime (otherwise cobra/mono would be perfect) for win. lua? haskell? ooc?","id":30065412242669568,"from_user_id":1291845,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"5912444","profile_image_url":"http://a2.twimg.com/profile_images/546261026/ssf0xg11_normal.jpg","created_at":"Wed, 26 Jan 2011 00:45:45 +0000","from_user":"shelarcy","id_str":"30063810773516288","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @Hackage: download 0.3.1.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/eHfiJB","id":30063810773516288,"from_user_id":5912444,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"135993","profile_image_url":"http://a2.twimg.com/profile_images/1190667086/myface2010small_normal.jpg","created_at":"Wed, 26 Jan 2011 00:41:00 +0000","from_user":"kudzu_naoki","id_str":"30062613287141376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u9b54\u6cd5Haskell\u5c11\u5973\u5019\u88dc\u3092\u63a2\u3059\u306e\u3082\u5927\u5909\u306a\u3093\u3060","id":30062613287141376,"from_user_id":135993,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"52620546","profile_image_url":"http://a1.twimg.com/profile_images/434693356/twitter-icon_normal.png","created_at":"Wed, 26 Jan 2011 00:40:25 +0000","from_user":"omasanori","id_str":"30062465656033280","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u9b54\u6cd5Haskell\u5c11\u5973\u306e\u4e00\u65e5\u306fGHC HEAD\u306e\u30d3\u30eb\u30c9\u304b\u3089\u59cb\u307e\u308b","id":30062465656033280,"from_user_id":52620546,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.movatwi.jp" rel="nofollow">www.movatwi.jp</a>"},{"from_user_id_str":"52620546","profile_image_url":"http://a1.twimg.com/profile_images/434693356/twitter-icon_normal.png","created_at":"Wed, 26 Jan 2011 00:37:12 +0000","from_user":"omasanori","id_str":"30061656331526144","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u50d5\u3068\u5951\u7d04\u3057\u3066\u9b54\u6cd5Haskell\u5c11\u5973\u306b\u306a\u308d\u3046\u3088\uff01","id":30061656331526144,"from_user_id":52620546,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"135993","profile_image_url":"http://a2.twimg.com/profile_images/1190667086/myface2010small_normal.jpg","created_at":"Wed, 26 Jan 2011 00:35:42 +0000","from_user":"kudzu_naoki","id_str":"30061282665168896","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u50d5\u3068\u5951\u7d04\u3057\u3066\u9b54\u6cd5Haskell\u5c11\u5973\u306b\u306a\u308d\u3046\u3088\uff01","id":30061282665168896,"from_user_id":135993,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"1631333","profile_image_url":"http://a1.twimg.com/profile_images/81268862/profile300_normal.jpg","created_at":"Wed, 26 Jan 2011 00:30:02 +0000","from_user":"qnighy","id_str":"30059855884582913","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u50d5\u3068\u5951\u7d04\u3057\u3066\u9b54\u6cd5Haskell\u5c11\u5973\u306b\u306a\u308d\u3046\u3088\uff01","id":30059855884582913,"from_user_id":1631333,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"9093754","profile_image_url":"http://a1.twimg.com/profile_images/99435906/PHD_3d_col_blk_normal.jpg","created_at":"Wed, 26 Jan 2011 00:26:20 +0000","from_user":"phdwine","id_str":"30058925516656640","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Last weekend of Tri Nations Tasting with PHD wines at Haskell Vineyards. Hope you didn't miss the Pinot Noir tasting last week !","id":30058925516656640,"from_user_id":9093754,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"2119923","profile_image_url":"http://a2.twimg.com/profile_images/1096701078/djayprofile_normal.jpg","created_at":"Wed, 26 Jan 2011 00:21:14 +0000","from_user":"djay75","id_str":"30057639543050240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @dnene: Skilled Calisthenics. Haskell code that outputs python which spits ruby which emits the haskell source. http://j.mp/YlQUL via @mfeathers","id":30057639543050240,"from_user_id":2119923,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"134323731","profile_image_url":"http://a2.twimg.com/profile_images/1225818824/IMG00518-20110125-1547_normal.jpg","created_at":"Wed, 26 Jan 2011 00:19:30 +0000","from_user":"PrinceOfBrkeley","id_str":"30057205554216960","metadata":{"result_type":"recent"},"to_user_id":167093027,"text":"@PayThaPrince go to haskell.","id":30057205554216960,"from_user_id":134323731,"to_user":"PayThaPrince","geo":null,"iso_language_code":"en","to_user_id_str":"167093027","source":"<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry\u00ae</a>"},{"from_user_id_str":"705857","profile_image_url":"http://a1.twimg.com/profile_images/429483912/ben_twitter_normal.jpg","created_at":"Wed, 26 Jan 2011 00:03:28 +0000","from_user":"bennadel","id_str":"30053166972141569","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Using #Homebrew to install Haskell - the last of the Seven Languages (in Seven Weeks) http://bit.ly/eA9Cv1 This has been some journey.","id":30053166972141569,"from_user_id":705857,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"251466","profile_image_url":"http://a2.twimg.com/profile_images/1194100934/pass_normal.jpg","created_at":"Wed, 26 Jan 2011 00:02:54 +0000","from_user":"simonszu","id_str":"30053025502466048","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Ouh yeah! Ich werde doch produktiv sein, diese Semesterferien. Ich werde funktional Programmieren lernen. #haskell, Baby.","id":30053025502466048,"from_user_id":251466,"geo":null,"iso_language_code":"de","to_user_id_str":null,"source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"357786","profile_image_url":"http://a0.twimg.com/profile_images/612044841/FM_2010_normal.jpg","created_at":"Tue, 25 Jan 2011 23:59:13 +0000","from_user":"diligiant","id_str":"30052100973006848","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @paulrbrown: "...we only discovered a single bug after compilation." (http://t.co/K0wlEYz) #haskell","id":30052100973006848,"from_user_id":357786,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"101597523","profile_image_url":"http://a1.twimg.com/profile_images/1206183256/2010-12-12-204902_normal.jpg","created_at":"Tue, 25 Jan 2011 23:54:46 +0000","from_user":"wlad_kent","id_str":"30050977964892160","metadata":{"result_type":"recent"},"to_user_id":86297184,"text":"@Nilson_Neto Isso eh bem basico. quando vc estiver estudando recurs\u00e3o em Haskell, ai vc vai ver oq eh papo de nerd - kkk - 1\u00ba periodo isso.","id":30050977964892160,"from_user_id":101597523,"to_user":"Nilson_Neto","geo":null,"iso_language_code":"pt","to_user_id_str":"86297184","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Tue, 25 Jan 2011 23:51:22 +0000","from_user":"listwarenet","id_str":"30050123383832577","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84336-haskell-cafe-monomorphic-let-bindings-and-darcs.html Haskell-cafe - Monomorph","id":30050123383832577,"from_user_id":144546280,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"5776901","profile_image_url":"http://a0.twimg.com/profile_images/472682157/lucabw_normal.JPG","created_at":"Tue, 25 Jan 2011 23:48:40 +0000","from_user":"lsbardel","id_str":"30049446469312512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Very interesting technology stack these guys use http://bit.ly/ghAjS7 #python #redis #haskell","id":30049446469312512,"from_user_id":5776901,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"3005901","profile_image_url":"http://a0.twimg.com/profile_images/278943006/Lone_Pine_Peak_-_Peter_200x200_normal.jpg","created_at":"Tue, 25 Jan 2011 23:45:48 +0000","from_user":"pmonks","id_str":"30048721110573056","metadata":{"result_type":"recent"},"to_user_id":203834278,"text":"@techielicous Haskell: http://bit.ly/gy3oFi ;-)","id":30048721110573056,"from_user_id":3005901,"to_user":"techielicous","geo":null,"iso_language_code":"en","to_user_id_str":"203834278","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"162697074","profile_image_url":"http://a2.twimg.com/profile_images/826205838/ryan3_normal.jpg","created_at":"Tue, 25 Jan 2011 23:44:47 +0000","from_user":"TheRonaldMCD","id_str":"30048468781244416","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Aldi Food Market (4122 Gaston Ave, Haskell, Dallas) http://4sq.com/ekqRY7","id":30048468781244416,"from_user_id":162697074,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"203834278","profile_image_url":"http://a0.twimg.com/profile_images/1223375080/me_normal.jpg","created_at":"Tue, 25 Jan 2011 23:44:04 +0000","from_user":"techielicous","id_str":"30048286589067264","metadata":{"result_type":"recent"},"to_user_id":3005901,"text":"@pmonks I was thinking Haskell or Scheme","id":30048286589067264,"from_user_id":203834278,"to_user":"pmonks","geo":null,"iso_language_code":"en","to_user_id_str":"3005901","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"537690","profile_image_url":"http://a3.twimg.com/profile_images/45665122/nushiostamp_normal.jpg","created_at":"Tue, 25 Jan 2011 23:38:14 +0000","from_user":"nushio","id_str":"30046818658164737","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u305d\u3046\u3044\u3084\u5951\u7d04\u306b\u3088\u308b\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u3068\u304b\u3042\u3063\u305f\u306a\u3002Haskell\u306a\u3093\u304b\u3088\u308a\u3042\u3063\u3061\u306e\u65b9\u304c\u9b54\u6cd5\u5c11\u5973\u547c\u3070\u308f\u308a\u306b\u3075\u3055\u308f\u3057\u3044\u3002","id":30046818658164737,"from_user_id":537690,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"181192","profile_image_url":"http://a2.twimg.com/profile_images/1089890701/q530888600_9828_normal.jpg","created_at":"Tue, 25 Jan 2011 23:38:03 +0000","from_user":"aodag","id_str":"30046772223016960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @omasanori: \u300c\u3082\u3046\u4f55\u5e74\u3082Haskell\u306e\u3053\u3068\u3057\u304b\u8003\u3048\u3066\u306a\u304b\u3063\u305f\u304b\u3089\u306a\u3001\u30eb\u30fc\u30d7\u306e\u4f7f\u3044\u65b9\u5fd8\u308c\u3066\u305f\u300d","id":30046772223016960,"from_user_id":181192,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.movatwi.jp" rel="nofollow">www.movatwi.jp</a>"},{"from_user_id_str":"5886055","profile_image_url":"http://a3.twimg.com/profile_images/85531669/ichi_normal.jpg","created_at":"Tue, 25 Jan 2011 23:37:53 +0000","from_user":"kanaya","id_str":"30046729243983873","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u9e97\u3057\u3044\u3002\u201c@omasanori: \u300c\u3082\u3046\u4f55\u5e74\u3082Haskell\u306e\u3053\u3068\u3057\u304b\u8003\u3048\u3066\u306a\u304b\u3063\u305f\u304b\u3089\u306a\u3001\u30eb\u30fc\u30d7\u306e\u4f7f\u3044\u65b9\u5fd8\u308c\u3066\u305f\u300d\u201d","id":30046729243983873,"from_user_id":5886055,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/app/twitter/id333903271?mt=8" rel="nofollow">Twitter for iPad</a>"},{"from_user_id_str":"52620546","profile_image_url":"http://a1.twimg.com/profile_images/434693356/twitter-icon_normal.png","created_at":"Tue, 25 Jan 2011 23:36:26 +0000","from_user":"omasanori","id_str":"30046367187476481","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u300c\u3082\u3046\u4f55\u5e74\u3082Haskell\u306e\u3053\u3068\u3057\u304b\u8003\u3048\u3066\u306a\u304b\u3063\u305f\u304b\u3089\u306a\u3001\u30eb\u30fc\u30d7\u306e\u4f7f\u3044\u65b9\u5fd8\u308c\u3066\u305f\u300d","id":30046367187476481,"from_user_id":52620546,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.movatwi.jp" rel="nofollow">www.movatwi.jp</a>"},{"from_user_id_str":"1659992","profile_image_url":"http://a1.twimg.com/profile_images/504488750/1_normal.jpg","created_at":"Tue, 25 Jan 2011 23:16:13 +0000","from_user":"finalfusion","id_str":"30041278544609280","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @necocen: Haskell\u306e\u30df\u30b5\u30ef\u3001\u3068\u3044\u3046\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u3066\u3071\u3063\u3068\u3057\u306a\u3044","id":30041278544609280,"from_user_id":1659992,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"272513","profile_image_url":"http://a2.twimg.com/profile_images/320244078/Mike_Painting2_normal.png","created_at":"Tue, 25 Jan 2011 23:05:09 +0000","from_user":"mikehadlow","id_str":"30038492373319680","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Just written the same simple program in C#, F# and Haskell: 18, 12 and 9 LoC respectively. And I'm much better at C# than F# or Haskell.","id":30038492373319680,"from_user_id":272513,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"89393264","profile_image_url":"http://a0.twimg.com/profile_images/1169486472/020_portland_me_normal.jpg","created_at":"Tue, 25 Jan 2011 23:01:28 +0000","from_user":"newsportlandme","id_str":"30037564589084673","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Governor's Choice to Run Maine DOC Under Scrutiny - MPBN: State Rep. Anne Haskell, a Portland Democrat, says Mai... http://bit.ly/fO30gC","id":30037564589084673,"from_user_id":89393264,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"38138","profile_image_url":"http://a3.twimg.com/profile_images/1212565885/Screen_shot_2011-01-11_at_5.28.47_PM_normal.png","created_at":"Tue, 25 Jan 2011 22:59:55 +0000","from_user":"michaelneale","id_str":"30037174615281664","metadata":{"result_type":"recent"},"to_user_id":null,"text":"The haskell EvilMangler http://t.co/P2Tls7J","id":30037174615281664,"from_user_id":38138,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"45692","profile_image_url":"http://a3.twimg.com/profile_images/1177741507/dogkarno_r_normal.jpg","created_at":"Tue, 25 Jan 2011 22:45:06 +0000","from_user":"karno","id_str":"30033448286552064","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u3063\u3066\u95a2\u6570\u306b\u30ab\u30ec\u30fc\u7c89\u3076\u3061\u8fbc\u3080\u3068\u304b\u306a\u3093\u3068\u304b","id":30033448286552064,"from_user_id":45692,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://yubitter.com/" rel="nofollow">yubitter</a>"},{"from_user_id_str":"27605","profile_image_url":"http://a2.twimg.com/profile_images/15826632/meron_normal.jpg","created_at":"Tue, 25 Jan 2011 22:44:23 +0000","from_user":"celeron1ghz","id_str":"30033268761956352","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @necocen: Haskell\u306e\u30df\u30b5\u30ef\u3001\u3068\u3044\u3046\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u3066\u3071\u3063\u3068\u3057\u306a\u3044","id":30033268761956352,"from_user_id":27605,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"12901","profile_image_url":"http://a1.twimg.com/profile_images/56091349/haruhi_nagato-Y_normal.jpg","created_at":"Tue, 25 Jan 2011 22:43:30 +0000","from_user":"necocen","id_str":"30033044035346432","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u307e\u3042Haskell\u77e5\u3089\u3093\u3057\u306d","id":30033044035346432,"from_user_id":12901,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"12901","profile_image_url":"http://a1.twimg.com/profile_images/56091349/haruhi_nagato-Y_normal.jpg","created_at":"Tue, 25 Jan 2011 22:42:54 +0000","from_user":"necocen","id_str":"30032894856531968","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u306e\u30df\u30b5\u30ef\u3001\u3068\u3044\u3046\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u3066\u3071\u3063\u3068\u3057\u306a\u3044","id":30032894856531968,"from_user_id":12901,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"10821270","profile_image_url":"http://a0.twimg.com/profile_images/1195474259/Salto_Marlon_normal.jpg","created_at":"Tue, 25 Jan 2011 22:35:09 +0000","from_user":"jjedMoriAnktah","id_str":"30030942106025984","metadata":{"result_type":"recent"},"to_user_id":null,"text":""A Haskell program that outputs a Python program that outputs a Ruby program that outputs the original Haskell program" http://is.gd/E6Julu","id":30030942106025984,"from_user_id":10821270,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"7554762","profile_image_url":"http://a0.twimg.com/profile_images/100515212/ajay-photo_normal.jpg","created_at":"Tue, 25 Jan 2011 22:34:30 +0000","from_user":"comatose_kid","id_str":"30030780205899776","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @bumptech: Bump Dev Blog - Why we use Haskell at Bump http://devblog.bu.mp/haskell-at-bump","id":30030780205899776,"from_user_id":7554762,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"148474705","profile_image_url":"http://a0.twimg.com/profile_images/1119234716/fur_hat_-_gilbeys_vodka_-_life_-_11-30-1962_normal.JPG","created_at":"Tue, 25 Jan 2011 22:29:19 +0000","from_user":"landmvintage","id_str":"30029476003840000","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @faerymoongodess: Magnificent Miriam Haskell Baroque Pearl Necklace by @MercyMadge http://etsy.me/hqRl51","id":30029476003840000,"from_user_id":148474705,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"37715508","profile_image_url":"http://a1.twimg.com/profile_images/1207891411/ballerina_normal.jpg","created_at":"Tue, 25 Jan 2011 22:24:52 +0000","from_user":"faerymoongodess","id_str":"30028356326002688","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Magnificent Miriam Haskell Baroque Pearl Necklace by @MercyMadge http://etsy.me/hqRl51","id":30028356326002688,"from_user_id":37715508,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Tue, 25 Jan 2011 22:17:16 +0000","from_user":"Hackage","id_str":"30026442456694784","metadata":{"result_type":"recent"},"to_user_id":null,"text":"base16-bytestring 0.1.0.0, added by BryanOSullivan: Fast base16 (hex) encoding and deconding for ByteStrings http://bit.ly/eu75TN","id":30026442456694784,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"199750997","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Tue, 25 Jan 2011 22:12:07 +0000","from_user":"benreads","id_str":"30025146991382528","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Writing Systems Software in a Functional Language -- brief, but fun. I want to see how well they can make Systems Haskell perform at scale.","id":30025146991382528,"from_user_id":199750997,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"35359797","profile_image_url":"http://a1.twimg.com/profile_images/1173453785/48893_521140819_1896062_q_normal.jpg","created_at":"Tue, 25 Jan 2011 22:09:45 +0000","from_user":"jcawthorne1","id_str":"30024549265309696","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Just saw Jeff Haskell give the middle finger!! Lol awesome","id":30024549265309696,"from_user_id":35359797,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Tue, 25 Jan 2011 22:06:44 +0000","from_user":"goodfox","id_str":"30023790381498369","metadata":{"result_type":"recent"},"to_user_id":null,"text":"At the Haskell Convocation. (@ Haskell Indian Nations U Auditorium) http://4sq.com/eKKXyn","id":30023790381498369,"from_user_id":13540930,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"14674418","profile_image_url":"http://a2.twimg.com/profile_images/238230125/IMG_1030-1_normal.jpg","created_at":"Tue, 25 Jan 2011 22:02:31 +0000","from_user":"sanityinc","id_str":"30022731919523840","metadata":{"result_type":"recent"},"to_user_id":371289,"text":"@xshay Haskell's great, but Clojure's similarly lazy in all the ways that matter, and is more practical for day-to-day use.","id":30022731919523840,"from_user_id":14674418,"to_user":"xshay","geo":null,"iso_language_code":"en","to_user_id_str":"371289","source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"371289","profile_image_url":"http://a2.twimg.com/profile_images/1113482439/me-brisbane_normal.jpg","created_at":"Tue, 25 Jan 2011 21:58:29 +0000","from_user":"xshay","id_str":"30021714444292096","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Just made a lazy sequence of prime numbers in haskell. I'm smitten.","id":30021714444292096,"from_user_id":371289,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"199453873","profile_image_url":"http://a3.twimg.com/a/1294785484/images/default_profile_3_normal.png","created_at":"Tue, 25 Jan 2011 21:48:40 +0000","from_user":"stackfeed","id_str":"30019243982454784","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Practical Scala reference manual, for searching things like method names: Hello, \n\nInspired by\nHaskell API Searc... http://bit.ly/g4zWZQ","id":30019243982454784,"from_user_id":199453873,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Tue, 25 Jan 2011 21:45:32 +0000","from_user":"aapnoot","id_str":"30018455189065728","metadata":{"result_type":"recent"},"to_user_id":null,"text":"download 0.3.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/i8mYvi","id":30018455189065728,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Tue, 25 Jan 2011 21:45:31 +0000","from_user":"aapnoot","id_str":"30018452601180160","metadata":{"result_type":"recent"},"to_user_id":null,"text":"download 0.3.1.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/eHfiJB","id":30018452601180160,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Tue, 25 Jan 2011 21:45:31 +0000","from_user":"Hackage","id_str":"30018451867176960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"download 0.3.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/i8mYvi","id":30018451867176960,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"138502705","profile_image_url":"http://a1.twimg.com/profile_images/1083845614/yclogo_normal.gif","created_at":"Tue, 25 Jan 2011 21:45:04 +0000","from_user":"newsyc100","id_str":"30018340839755777","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell improves log processing 4x over Python http://devblog.bu.mp/haskell-at-bump (http://bit.ly/gQxxR8)","id":30018340839755777,"from_user_id":138502705,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://news.ycombinator.com" rel="nofollow">newsyc</a>"},{"from_user_id_str":"1578246","profile_image_url":"http://a0.twimg.com/profile_images/59312315/avatar_simpson_small_normal.jpg","created_at":"Tue, 25 Jan 2011 21:43:32 +0000","from_user":"magthe","id_str":"30017953801969665","metadata":{"result_type":"recent"},"to_user_id":null,"text":"New version of download uploaded to #hackage #haskell","id":30017953801969665,"from_user_id":1578246,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://api.supertweet.net" rel="nofollow">MyAuth API Proxy</a>"},{"from_user_id_str":"135838970","profile_image_url":"http://a2.twimg.com/profile_images/1079929891/logo_normal.png","created_at":"Tue, 25 Jan 2011 21:37:51 +0000","from_user":"reward999","id_str":"30016525180084224","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Found Great Dane (Main & Haskell- Dallas): We found a great dane. 214-712-0000 http://bit.ly/fQ8iBw","id":30016525180084224,"from_user_id":135838970,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"137719265","profile_image_url":"http://a2.twimg.com/profile_images/1092224079/8__4__normal.jpg","created_at":"Tue, 25 Jan 2011 21:34:22 +0000","from_user":"WeiMatas","id_str":"30015646020411392","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Fourth day Rez party Eddie Haskell County in second life \u2013 which took place in cabaret Tadd","id":30015646020411392,"from_user_id":137719265,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://dlvr.it" rel="nofollow">dlvr.it</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Tue, 25 Jan 2011 21:33:21 +0000","from_user":"listwarenet","id_str":"30015392571195392","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/83889-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Haskell-cafe -","id":30015392571195392,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"}],"max_id":30121530767708160,"since_id":0,"refresh_url":"?since_id=30121530767708160&q=haskell","next_page":"?page=2&max_id=30121530767708160&rpp=100&q=haskell","results_per_page":100,"page":1,"completed_in":1.195569,"since_id_str":"0","max_id_str":"30121530767708160","query":"haskell"}
benchmarks/json-data/twitter20.json view
@@ -1,1 +1,1 @@-{"results":[{"from_user_id_str":"166199691","profile_image_url":"http://a2.twimg.com/profile_images/1252958188/38_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"_classicc","id_str":"41191052790603776","metadata":{"result_type":"recent"},"to_user_id":null,"text":"my twitter is actin slow today.","id":41191052790603776,"from_user_id":166199691,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"138835410","profile_image_url":"http://a1.twimg.com/profile_images/1250985094/243321801_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"amereronday","id_str":"41191050307567616","metadata":{"result_type":"recent"},"to_user_id":null,"text":"twitter jail, here i come.","id":41191050307567616,"from_user_id":138835410,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"359548","profile_image_url":"http://a2.twimg.com/profile_images/53612334/don_otvos_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"donnyo","id_str":"41191050110451712","metadata":{"result_type":"recent"},"to_user_id":7074534,"text":"@stlsmallbiz I see there is currently a Twitter promo too....tempting....","id":41191050110451712,"from_user_id":359548,"to_user":"stlsmallbiz","geo":null,"iso_language_code":"en","place":{"id":"82b7b2f97b12261d","type":"poi","full_name":"Yammer Inc, San Francisco"},"to_user_id_str":"7074534","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"122523770","profile_image_url":"http://a0.twimg.com/profile_images/1073533262/11646_1076222405045_1810798478_156114_3663737_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"msBreChan","id_str":"41191049720238080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"so twitter gt spam now -_-","id":41191049720238080,"from_user_id":122523770,"geo":{"type":"Point","coordinates":[35.2213,-80.8276]},"iso_language_code":"en","place":{"id":"4d5ed95f830e9b41","type":"neighborhood","full_name":"Elizabeth, Charlotte"},"to_user_id_str":null,"source":"<a href="http://mobile.twitter.com" rel="nofollow">Twitter for Android</a>"},{"from_user_id_str":"229024950","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_6_normal.png","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"NinaMaechik","id_str":"41191047853912064","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Glad I can remember my twitter password! LOL! Hugs to Nick from his aunties...","id":41191047853912064,"from_user_id":229024950,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"215545822","profile_image_url":"http://a2.twimg.com/profile_images/1239909540/RTL_normal.png","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"RightToLaugh","id_str":"41191047371558912","metadata":{"result_type":"recent"},"to_user_id":null,"text":"#Bacon wrapped dates http://bit.ly/hUxVC9 Just like my grandma used to make http://twitter.com/#","id":41191047371558912,"from_user_id":215545822,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"217845526","profile_image_url":"http://a0.twimg.com/sticky/default_profile_images/default_profile_3_normal.png","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"TheShoeLooker","id_str":"41191047052804096","metadata":{"result_type":"recent"},"to_user_id":38033240,"text":"@ShoeDazzle love love love to twitter or blog about your deals and shoes!\ntheshoelooker.blogspot.com","id":41191047052804096,"from_user_id":217845526,"to_user":"shoedazzle","geo":null,"iso_language_code":"en","to_user_id_str":"38033240","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"24953438","profile_image_url":"http://a3.twimg.com/profile_images/1181252763/76820_10150100014748783_677998782_7386695_4377006_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"liljermaine32","id_str":"41191046025056256","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Twitter fam I gotta question 4 ya is texas south or midwest #arguments","id":41191046025056256,"from_user_id":24953438,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://mobile.twitter.com" rel="nofollow">Twitter for Android</a>"},{"from_user_id_str":"122451024","profile_image_url":"http://a2.twimg.com/profile_images/1143400129/100706-ETCanada_201134_1__normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"Kim_DEon","id_str":"41191045161164801","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Help @CARE @EvaLongoria and ME use Twitter to change the lives of girls in poverty across the world! Ready? Go to http://TwitChange.com NOW!","id":41191045161164801,"from_user_id":122451024,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"128351479","profile_image_url":"http://a3.twimg.com/profile_images/1150198829/Kirby_Photo__edit__normal.JPG","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"TheDaveKirby","id_str":"41191043894493184","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Maybe its time to clean house...MY HOUSE http://bit.ly/ejG22P","id":41191043894493184,"from_user_id":128351479,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"87512773","profile_image_url":"http://a0.twimg.com/profile_images/1252511106/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"supportthehood","id_str":"41191043206610946","metadata":{"result_type":"recent"},"to_user_id":2467330,"text":"@eastcoastmp3 #FF it's the way twitter works !!!","id":41191043206610946,"from_user_id":87512773,"to_user":"eastcoastmp3","geo":null,"iso_language_code":"en","to_user_id_str":"2467330","source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"149894545","profile_image_url":"http://a0.twimg.com/profile_images/1219334400/patrick_camo_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"suburbpat","id_str":"41191040912330752","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I havent had a rib session on twitter in a while.......I wanna Rib with a nigga with alot followers lol","id":41191040912330752,"from_user_id":149894545,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"97749622","profile_image_url":"http://a0.twimg.com/profile_images/1254640781/IMG1633A_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"jrricardosantos","id_str":"41191040547430400","metadata":{"result_type":"recent"},"to_user_id":101017476,"text":"@yofzs pq tirou o CAPS LOCK? kkkk tava bem legal...hehehe eu estou no t\u00e9dio...kkk tbm estou no twitter e msn..aff!!","id":41191040547430400,"from_user_id":97749622,"to_user":"yofzs","geo":null,"iso_language_code":"en","to_user_id_str":"101017476","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"94381536","profile_image_url":"http://a1.twimg.com/profile_images/1174777929/41509_100001699300415_3521888_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"DonNieves","id_str":"41191038978752512","metadata":{"result_type":"recent"},"to_user_id":151926400,"text":"@TiiH13 cheira meu ovo, no email, no orkut, no msn, no facebook, no twitter, no skype, no spark, no ICQ e no google talk","id":41191038978752512,"from_user_id":94381536,"to_user":"TiiH13","geo":null,"iso_language_code":"en","to_user_id_str":"151926400","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"211858432","profile_image_url":"http://a3.twimg.com/profile_images/1231906180/JonasBrothers_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"OriginalJBfans","id_str":"41191038328651776","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I literally forgot about this twitter... so whats occuring followers?","id":41191038328651776,"from_user_id":211858432,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"90317132","profile_image_url":"http://a3.twimg.com/profile_images/1230085056/254101635_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"Just2smooth","id_str":"41191036936126464","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Wassup twitter","id":41191036936126464,"from_user_id":90317132,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://ubersocial.com" rel="nofollow">\u00dcberSocial</a>"},{"from_user_id_str":"144771504","profile_image_url":"http://a1.twimg.com/profile_images/1243343836/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"ima_b_b_badman","id_str":"41191036638339072","metadata":{"result_type":"recent"},"to_user_id":null,"text":"i been M.I.A. all day twitter my bad","id":41191036638339072,"from_user_id":144771504,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"207922664","profile_image_url":"http://a2.twimg.com/profile_images/1237106108/258356167_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:22 +0000","from_user":"itsthecarter_","id_str":"41191036013391873","metadata":{"result_type":"recent"},"to_user_id":null,"text":"twitter is a stupid addiction.","id":41191036013391873,"from_user_id":207922664,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://ubersocial.com" rel="nofollow">\u00dcberSocial</a>"},{"from_user_id_str":"150000649","profile_image_url":"http://a0.twimg.com/profile_images/1237789059/belllaa_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:22 +0000","from_user":"angelicabrvo","id_str":"41191035707207680","metadata":{"result_type":"recent"},"to_user_id":null,"text":"que hubo twitter? huy que feoxd","id":41191035707207680,"from_user_id":150000649,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry\u00ae</a>"},{"from_user_id_str":"185713003","profile_image_url":"http://a2.twimg.com/profile_images/1191421540/163229_177015295661467_154687431227587_492170_2147500_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:22 +0000","from_user":"downbytheshores","id_str":"41191033945595905","metadata":{"result_type":"recent"},"to_user_id":null,"text":"follow us on twitter\nwww.twitter.com/downbytheshores http://fb.me/DhDS915e","id":41191033945595905,"from_user_id":185713003,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"}],"max_id":41191052790603776,"since_id":38643906774044672,"refresh_url":"?since_id=41191052790603776&q=twitter","next_page":"?page=2&max_id=41191052790603776&rpp=20&lang=en&q=twitter","results_per_page":20,"page":1,"completed_in":0.128719,"warning":"adjusted since_id to 38643906774044672 (), requested since_id was older than allowed -- since_id removed for pagination.","since_id_str":"38643906774044672","max_id_str":"41191052790603776","query":"twitter"}+{"results":[{"from_user_id_str":"166199691","profile_image_url":"http://a2.twimg.com/profile_images/1252958188/38_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"_classicc","id_str":"41191052790603776","metadata":{"result_type":"recent"},"to_user_id":null,"text":"my twitter is actin slow today.","id":41191052790603776,"from_user_id":166199691,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"138835410","profile_image_url":"http://a1.twimg.com/profile_images/1250985094/243321801_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"amereronday","id_str":"41191050307567616","metadata":{"result_type":"recent"},"to_user_id":null,"text":"twitter jail, here i come.","id":41191050307567616,"from_user_id":138835410,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"359548","profile_image_url":"http://a2.twimg.com/profile_images/53612334/don_otvos_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"donnyo","id_str":"41191050110451712","metadata":{"result_type":"recent"},"to_user_id":7074534,"text":"@stlsmallbiz I see there is currently a Twitter promo too....tempting....","id":41191050110451712,"from_user_id":359548,"to_user":"stlsmallbiz","geo":null,"iso_language_code":"en","place":{"id":"82b7b2f97b12261d","type_":"poi","full_name":"Yammer Inc, San Francisco"},"to_user_id_str":"7074534","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"122523770","profile_image_url":"http://a0.twimg.com/profile_images/1073533262/11646_1076222405045_1810798478_156114_3663737_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"msBreChan","id_str":"41191049720238080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"so twitter gt spam now -_-","id":41191049720238080,"from_user_id":122523770,"geo":{"type_":"Point","coordinates":[35.2213,-80.8276]},"iso_language_code":"en","place":{"id":"4d5ed95f830e9b41","type_":"neighborhood","full_name":"Elizabeth, Charlotte"},"to_user_id_str":null,"source":"<a href="http://mobile.twitter.com" rel="nofollow">Twitter for Android</a>"},{"from_user_id_str":"229024950","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_6_normal.png","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"NinaMaechik","id_str":"41191047853912064","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Glad I can remember my twitter password! LOL! Hugs to Nick from his aunties...","id":41191047853912064,"from_user_id":229024950,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"215545822","profile_image_url":"http://a2.twimg.com/profile_images/1239909540/RTL_normal.png","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"RightToLaugh","id_str":"41191047371558912","metadata":{"result_type":"recent"},"to_user_id":null,"text":"#Bacon wrapped dates http://bit.ly/hUxVC9 Just like my grandma used to make http://twitter.com/#","id":41191047371558912,"from_user_id":215545822,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"217845526","profile_image_url":"http://a0.twimg.com/sticky/default_profile_images/default_profile_3_normal.png","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"TheShoeLooker","id_str":"41191047052804096","metadata":{"result_type":"recent"},"to_user_id":38033240,"text":"@ShoeDazzle love love love to twitter or blog about your deals and shoes!\ntheshoelooker.blogspot.com","id":41191047052804096,"from_user_id":217845526,"to_user":"shoedazzle","geo":null,"iso_language_code":"en","to_user_id_str":"38033240","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"24953438","profile_image_url":"http://a3.twimg.com/profile_images/1181252763/76820_10150100014748783_677998782_7386695_4377006_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"liljermaine32","id_str":"41191046025056256","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Twitter fam I gotta question 4 ya is texas south or midwest #arguments","id":41191046025056256,"from_user_id":24953438,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://mobile.twitter.com" rel="nofollow">Twitter for Android</a>"},{"from_user_id_str":"122451024","profile_image_url":"http://a2.twimg.com/profile_images/1143400129/100706-ETCanada_201134_1__normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"Kim_DEon","id_str":"41191045161164801","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Help @CARE @EvaLongoria and ME use Twitter to change the lives of girls in poverty across the world! Ready? Go to http://TwitChange.com NOW!","id":41191045161164801,"from_user_id":122451024,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"128351479","profile_image_url":"http://a3.twimg.com/profile_images/1150198829/Kirby_Photo__edit__normal.JPG","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"TheDaveKirby","id_str":"41191043894493184","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Maybe its time to clean house...MY HOUSE http://bit.ly/ejG22P","id":41191043894493184,"from_user_id":128351479,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"87512773","profile_image_url":"http://a0.twimg.com/profile_images/1252511106/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"supportthehood","id_str":"41191043206610946","metadata":{"result_type":"recent"},"to_user_id":2467330,"text":"@eastcoastmp3 #FF it's the way twitter works !!!","id":41191043206610946,"from_user_id":87512773,"to_user":"eastcoastmp3","geo":null,"iso_language_code":"en","to_user_id_str":"2467330","source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"149894545","profile_image_url":"http://a0.twimg.com/profile_images/1219334400/patrick_camo_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"suburbpat","id_str":"41191040912330752","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I havent had a rib session on twitter in a while.......I wanna Rib with a nigga with alot followers lol","id":41191040912330752,"from_user_id":149894545,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"97749622","profile_image_url":"http://a0.twimg.com/profile_images/1254640781/IMG1633A_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"jrricardosantos","id_str":"41191040547430400","metadata":{"result_type":"recent"},"to_user_id":101017476,"text":"@yofzs pq tirou o CAPS LOCK? kkkk tava bem legal...hehehe eu estou no t\u00e9dio...kkk tbm estou no twitter e msn..aff!!","id":41191040547430400,"from_user_id":97749622,"to_user":"yofzs","geo":null,"iso_language_code":"en","to_user_id_str":"101017476","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"94381536","profile_image_url":"http://a1.twimg.com/profile_images/1174777929/41509_100001699300415_3521888_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"DonNieves","id_str":"41191038978752512","metadata":{"result_type":"recent"},"to_user_id":151926400,"text":"@TiiH13 cheira meu ovo, no email, no orkut, no msn, no facebook, no twitter, no skype, no spark, no ICQ e no google talk","id":41191038978752512,"from_user_id":94381536,"to_user":"TiiH13","geo":null,"iso_language_code":"en","to_user_id_str":"151926400","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"211858432","profile_image_url":"http://a3.twimg.com/profile_images/1231906180/JonasBrothers_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"OriginalJBfans","id_str":"41191038328651776","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I literally forgot about this twitter... so whats occuring followers?","id":41191038328651776,"from_user_id":211858432,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"90317132","profile_image_url":"http://a3.twimg.com/profile_images/1230085056/254101635_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"Just2smooth","id_str":"41191036936126464","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Wassup twitter","id":41191036936126464,"from_user_id":90317132,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://ubersocial.com" rel="nofollow">\u00dcberSocial</a>"},{"from_user_id_str":"144771504","profile_image_url":"http://a1.twimg.com/profile_images/1243343836/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"ima_b_b_badman","id_str":"41191036638339072","metadata":{"result_type":"recent"},"to_user_id":null,"text":"i been M.I.A. all day twitter my bad","id":41191036638339072,"from_user_id":144771504,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"207922664","profile_image_url":"http://a2.twimg.com/profile_images/1237106108/258356167_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:22 +0000","from_user":"itsthecarter_","id_str":"41191036013391873","metadata":{"result_type":"recent"},"to_user_id":null,"text":"twitter is a stupid addiction.","id":41191036013391873,"from_user_id":207922664,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://ubersocial.com" rel="nofollow">\u00dcberSocial</a>"},{"from_user_id_str":"150000649","profile_image_url":"http://a0.twimg.com/profile_images/1237789059/belllaa_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:22 +0000","from_user":"angelicabrvo","id_str":"41191035707207680","metadata":{"result_type":"recent"},"to_user_id":null,"text":"que hubo twitter? huy que feoxd","id":41191035707207680,"from_user_id":150000649,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry\u00ae</a>"},{"from_user_id_str":"185713003","profile_image_url":"http://a2.twimg.com/profile_images/1191421540/163229_177015295661467_154687431227587_492170_2147500_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:22 +0000","from_user":"downbytheshores","id_str":"41191033945595905","metadata":{"result_type":"recent"},"to_user_id":null,"text":"follow us on twitter\nwww.twitter.com/downbytheshores http://fb.me/DhDS915e","id":41191033945595905,"from_user_id":185713003,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"}],"max_id":41191052790603776,"since_id":38643906774044672,"refresh_url":"?since_id=41191052790603776&q=twitter","next_page":"?page=2&max_id=41191052790603776&rpp=20&lang=en&q=twitter","results_per_page":20,"page":1,"completed_in":0.128719,"warning":"adjusted since_id to 38643906774044672 (), requested since_id was older than allowed -- since_id removed for pagination.","since_id_str":"38643906774044672","max_id_str":"41191052790603776","query":"twitter"}
benchmarks/json-data/twitter50.json view
@@ -1,1 +1,1 @@-{"results":[{"from_user_id_str":"207858021","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 04:30:38 +0000","from_user":"pboudarga","id_str":"30120402839666689","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Rolla Sushi Grill (27737 Bouquet Canyon Road, #106, Btw Haskell Canyon and Rosedell Drive, Saugus) http://4sq.com/gqqdhs","id":30120402839666689,"from_user_id":207858021,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"69988683","profile_image_url":"http://a0.twimg.com/profile_images/1211955817/avatar_7888_normal.gif","created_at":"Wed, 26 Jan 2011 04:25:23 +0000","from_user":"YNK33","id_str":"30119083059978240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"hsndfile 0.5.0: Free and open source Haskell bindings for libsndfile http://bit.ly/gHaBWG Mac Os","id":30119083059978240,"from_user_id":69988683,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"81492","profile_image_url":"http://a1.twimg.com/profile_images/423894208/Picture_7_normal.jpg","created_at":"Wed, 26 Jan 2011 04:24:28 +0000","from_user":"satzz","id_str":"30118851488251904","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Emacs\u306e\u30e2\u30fc\u30c9\u8868\u793a\u304c\u4eca(Ruby Controller Outputz RoR Flymake REl hs)\u3068\u306a\u3063\u3066\u3066\u3088\u304f\u308f\u304b\u3089\u306a\u3044\u3093\u3060\u3051\u3069\u6700\u5f8c\u306eREl\u3068\u304bhs\u3063\u3066\u4f55\u3060\u308d\u3046\u2026haskell\u3068\u304b2\u5e74\u4ee5\u4e0a\u66f8\u3044\u3066\u306a\u3044\u3051\u3069\u2026","id":30118851488251904,"from_user_id":81492,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"9518356","profile_image_url":"http://a2.twimg.com/profile_images/119165723/ocaml-icon_normal.png","created_at":"Wed, 26 Jan 2011 04:19:19 +0000","from_user":"planet_ocaml","id_str":"30117557788741632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I so miss #haskell type classes in #ocaml - i want to do something like refinement. Also why does ocaml not have... http://bit.ly/geYRwt","id":30117557788741632,"from_user_id":9518356,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"218059","profile_image_url":"http://a1.twimg.com/profile_images/1053837723/twitter-icon9_normal.jpg","created_at":"Wed, 26 Jan 2011 04:16:32 +0000","from_user":"aprikip","id_str":"30116854940835840","metadata":{"result_type":"recent"},"to_user_id":null,"text":"yatex-mode\u3084haskell-mode\u306e\u3053\u3068\u3067\u3059\u306d\u3001\u308f\u304b\u308a\u307e\u3059\u3002","id":30116854940835840,"from_user_id":218059,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sites.google.com/site/yorufukurou/" rel="nofollow">YoruFukurou</a>"},{"from_user_id_str":"216363","profile_image_url":"http://a1.twimg.com/profile_images/72454310/Tim-Avatar_normal.png","created_at":"Wed, 26 Jan 2011 04:15:30 +0000","from_user":"dysinger","id_str":"30116594684264448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell in Hawaii tonight for me... #fun","id":30116594684264448,"from_user_id":216363,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.nambu.com/" rel="nofollow">Nambu</a>"},{"from_user_id_str":"1774820","profile_image_url":"http://a2.twimg.com/profile_images/61169291/dan_desert_thumb_normal.jpg","created_at":"Wed, 26 Jan 2011 04:13:36 +0000","from_user":"DanMil","id_str":"30116117682851840","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire @tomheon Haskell isn't a language, it's a belief system. A seductive one...","id":30116117682851840,"from_user_id":1774820,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"659256","profile_image_url":"http://a0.twimg.com/profile_images/746976711/angular-final_normal.jpg","created_at":"Wed, 26 Jan 2011 04:11:06 +0000","from_user":"djspiewak","id_str":"30115488931520512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"One of the very nice things about Haskell as opposed to SML is the reduced proliferation of identifiers (e.g. andb, orb, etc). #typeclasses","id":30115488931520512,"from_user_id":659256,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 04:06:12 +0000","from_user":"listwarenet","id_str":"30114255890026496","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84752-re-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Re: Haskell-c","id":30114255890026496,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 04:01:29 +0000","from_user":"ojrac","id_str":"30113067333324800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tomheon: @ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30113067333324800,"from_user_id":1594784,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"207589736","profile_image_url":"http://a3.twimg.com/profile_images/1225527428/headshot_1_normal.jpg","created_at":"Wed, 26 Jan 2011 04:00:13 +0000","from_user":"ashleevelazq101","id_str":"30112747555397632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/dONnpn","id":30112747555397632,"from_user_id":207589736,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"Hackage","id_str":"30112192346984448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112192346984448,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"aapnoot","id_str":"30112191881420800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112191881420800,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"8530482","profile_image_url":"http://a2.twimg.com/profile_images/137867266/n608671563_7396_normal.jpg","created_at":"Wed, 26 Jan 2011 03:50:12 +0000","from_user":"jeffmclamb","id_str":"30110229207187456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Angel - daemon to run and monitor processes like daemontools or god, written in Haskell http://ff.im/-wNyLk","id":30110229207187456,"from_user_id":8530482,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://friendfeed.com" rel="nofollow">FriendFeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:46:01 +0000","from_user":"tomheon","id_str":"30109174645919744","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30109174645919744,"from_user_id":177539201,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 03:44:34 +0000","from_user":"ojrac","id_str":"30108808684503040","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire @tomheon Why are you making me curious about Haskell? I LIKE not knowing what monad means!!","id":30108808684503040,"from_user_id":1594784,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"23750094","profile_image_url":"http://a0.twimg.com/profile_images/951373780/Moeinthecar_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:54 +0000","from_user":"shokalshab","id_str":"30108140443795456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Magnitude Cheer @ Gymnastics Olympica USA (7735 Haskell Ave., btw Saticoy & Strathern, Van Nuys) http://4sq.com/gmXfaL","id":30108140443795456,"from_user_id":23750094,"geo":null,"iso_language_code":"en","place":{"id":"4e4a2a2f86cb2946","type":"poi","full_name":"Gymnastics Olympica USA, Van Nuys"},"to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"8135112","profile_image_url":"http://a0.twimg.com/profile_images/1165240350/LIMITED_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:35 +0000","from_user":"Claricei","id_str":"30108059208515584","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @kristenmchugh22: @KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30108059208515584,"from_user_id":8135112,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:40:02 +0000","from_user":"chewedwire","id_str":"30107670367182848","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon Cool, I'll take a look. I feel like I should mention this: http://bit.ly/hVstDM","id":30107670367182848,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"8679778","profile_image_url":"http://a3.twimg.com/profile_images/1195318056/me_nyc_12_18_10_icon_normal.jpg","created_at":"Wed, 26 Jan 2011 03:38:42 +0000","from_user":"kristenmchugh22","id_str":"30107332381777920","metadata":{"result_type":"recent"},"to_user_id":756269,"text":"@KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30107332381777920,"from_user_id":8679778,"to_user":"KeithOlbermann","geo":null,"iso_language_code":"en","to_user_id_str":"756269","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"103316559","profile_image_url":"http://a1.twimg.com/profile_images/1179458751/bc3beab4-d59d-4e78-b13b-50747986cfa2_normal.png","created_at":"Wed, 26 Jan 2011 03:36:15 +0000","from_user":"cityslikr","id_str":"30106719153557504","metadata":{"result_type":"recent"},"to_user_id":null,"text":""Social safety net into a hammock." So says Eddie Haskell with the GOP response. #SOTU","id":30106719153557504,"from_user_id":103316559,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry\u00ae</a>"},{"from_user_id_str":"169063143","profile_image_url":"http://a0.twimg.com/profile_images/1160506212/9697_1_normal.gif","created_at":"Wed, 26 Jan 2011 03:31:52 +0000","from_user":"wrkforce_safety","id_str":"30105614919143424","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/gA60C1","id":30105614919143424,"from_user_id":169063143,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:29:40 +0000","from_user":"tomheon","id_str":"30105060960632832","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire Great book on Haskell: http://oreilly.com/catalog/9780596514983","id":30105060960632832,"from_user_id":177539201,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"782692","profile_image_url":"http://a0.twimg.com/profile_images/1031304589/Profile.2007.1_normal.jpg","created_at":"Wed, 26 Jan 2011 03:29:19 +0000","from_user":"turnageb","id_str":"30104974591533057","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @ovillalon: Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104974591533057,"from_user_id":782692,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:28:04 +0000","from_user":"chewedwire","id_str":"30104657267265536","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon I always loved the pattern matching in SML and it looks like Haskell is MUCH better at it. I'm messing around now at tryhaskell.org","id":30104657267265536,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"12834082","profile_image_url":"http://a3.twimg.com/profile_images/1083036140/mugshot_normal.png","created_at":"Wed, 26 Jan 2011 03:28:01 +0000","from_user":"ovillalon","id_str":"30104647213518848","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104647213518848,"from_user_id":12834082,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:26:02 +0000","from_user":"goodfox","id_str":"30104146455560192","metadata":{"result_type":"recent"},"to_user_id":10226179,"text":"@billykeene22 Bordeaux is one of my heroes. I was so excited when he accepted the invitation to campus. He's been a great friend to Haskell.","id":30104146455560192,"from_user_id":13540930,"to_user":"billykeene22","geo":null,"iso_language_code":"en","to_user_id_str":"10226179","source":"<a href="http://www.ubertwitter.com/bb/download.php" rel="nofollow">\u00dcberTwitter</a>"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 03:25:18 +0000","from_user":"josej30","id_str":"30103962313031681","metadata":{"result_type":"recent"},"to_user_id":14870909,"text":"@cris7ian Ahh bueno multiparadigma ya es respetable :) Empezar\u00e9 a explotar la parte funcional de los lenguajes ahora #Haskell","id":30103962313031681,"from_user_id":18616016,"to_user":"Cris7ian","geo":null,"iso_language_code":"es","to_user_id_str":"14870909","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"14870909","profile_image_url":"http://a2.twimg.com/profile_images/1176930429/oso_yo_normal.png","created_at":"Wed, 26 Jan 2011 03:23:43 +0000","from_user":"Cris7ian","id_str":"30103562360983553","metadata":{"result_type":"recent"},"to_user_id":18616016,"text":"@josej30 hahaha no, es multiparadigma y es bastante lazy. Nothing like haskell, pero s\u00ed, el de Flash","id":30103562360983553,"from_user_id":14870909,"to_user":"josej30","geo":null,"iso_language_code":"es","to_user_id_str":"18616016","source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"2421643","profile_image_url":"http://a0.twimg.com/profile_images/1190361665/ernestgrumbles-17_normal.jpg","created_at":"Wed, 26 Jan 2011 03:20:24 +0000","from_user":"ernestgrumbles","id_str":"30102730756333568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Wow... WolframAlpha did not know who Eddie Haskell is. Guess I'll never use that "knowledge engine" again.","id":30102730756333568,"from_user_id":2421643,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:14:21 +0000","from_user":"chewedwire","id_str":"30101204428132352","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon How is Haskell better/different from CL or Scheme? I honestly don't know, although I'm becoming more curious.","id":30101204428132352,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:06:54 +0000","from_user":"goodfox","id_str":"30099329809129473","metadata":{"result_type":"recent"},"to_user_id":null,"text":"A day of vision & speeches. #SOTU now. And a wonderful Haskell Convocation address earlier today by Sinte Gleske President Lionel Bordeaux.","id":30099329809129473,"from_user_id":13540930,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.ubertwitter.com/bb/download.php" rel="nofollow">\u00dcberTwitter</a>"},{"from_user_id_str":"119185220","profile_image_url":"http://a0.twimg.com/profile_images/1089027228/dfg_normal.jpg","created_at":"Wed, 26 Jan 2011 03:03:38 +0000","from_user":"LaLiciouz_03","id_str":"30098510623805440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"The Game with the girl room 330 Haskell follow us...","id":30098510623805440,"from_user_id":119185220,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 02:57:25 +0000","from_user":"josej30","id_str":"30096946144215040","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Voy a extra\u00f1ar Haskell cuando regrese al mundo imperativo. Hay alg\u00fan lenguaje imperativo que tenga este poder funcional? #ci3661","id":30096946144215040,"from_user_id":18616016,"geo":null,"iso_language_code":"es","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 02:55:32 +0000","from_user":"Hackage","id_str":"30096471814574080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"comonad-transformers 0.9.0, added by EdwardKmett: Haskell 98 comonad transformers http://bit.ly/h6xIsf","id":30096471814574080,"from_user_id":17671137,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 02:48:12 +0000","from_user":"tomheon","id_str":"30094626920603649","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Every time I look at Haskell I love it more.","id":30094626920603649,"from_user_id":177539201,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"60792568","profile_image_url":"http://a0.twimg.com/profile_images/1203647517/glenda-flash_normal.jpg","created_at":"Wed, 26 Jan 2011 02:40:42 +0000","from_user":"r_takaishi","id_str":"30092735935422464","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u3088\u308aD\u8a00\u8a9e\u304c\u4e0a\u3068\u306f\u601d\u308f\u306a\u304b\u3063\u305f\uff0e http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html","id":30092735935422464,"from_user_id":60792568,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twmode.sf.net/" rel="nofollow">twmode</a>"},{"from_user_id_str":"160145510","profile_image_url":"http://a0.twimg.com/profile_images/1218108166/going_galt_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:31 +0000","from_user":"wtp1787","id_str":"30092439653974018","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @KLSouth: Eddie Haskell Goes to Washington... "You look really nice tonight, Ms Cleaver"","id":30092439653974018,"from_user_id":160145510,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"96616016","profile_image_url":"http://a1.twimg.com/profile_images/1196978169/Picture0002_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:20 +0000","from_user":"MelissaRNMBA","id_str":"30092392203816960","metadata":{"result_type":"recent"},"to_user_id":14862975,"text":"@KLSouth At least Eddie Haskell was entertaining.","id":30092392203816960,"from_user_id":96616016,"to_user":"KLSouth","geo":null,"iso_language_code":"en","to_user_id_str":"14862975","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"14862975","profile_image_url":"http://a0.twimg.com/profile_images/421596393/kls_4_normal.JPG","created_at":"Wed, 26 Jan 2011 02:38:29 +0000","from_user":"KLSouth","id_str":"30092178327871489","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Eddie Haskell Goes to Washington... "You look really nice tonight, Ms Cleaver"","id":30092178327871489,"from_user_id":14862975,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 02:36:17 +0000","from_user":"listwarenet","id_str":"30091626869161984","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84641-haskell-beginners-wildcards-in-expressions.html Haskell-beginners - Wild","id":30091626869161984,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"24538048","profile_image_url":"http://a2.twimg.com/profile_images/1117267605/rope_normal.jpg","created_at":"Wed, 26 Jan 2011 02:23:14 +0000","from_user":"dbph","id_str":"30088341030440960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @dnene: Skilled Calisthenics. Haskell code that outputs python which spits ruby which emits the haskell source. http://j.mp/YlQUL via @mfeathers","id":30088341030440960,"from_user_id":24538048,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:58:31 +0000","from_user":"YubaVetTech","id_str":"30082124207886336","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigious Hayward Award for \u2018Excellence in Education\u2019. This award honors... http://fb.me/QgQCxd74","id":30082124207886336,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:56:04 +0000","from_user":"YubaVetTech","id_str":"30081505476743168","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigous Haward Award for Excellence in Education. This award honors... http://fb.me/PC9mYmCR","id":30081505476743168,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:43:50 +0000","from_user":"Verus","id_str":"30078427155406848","metadata":{"result_type":"recent"},"to_user_id":79273052,"text":"@kami_joe \u3044\u3084\uff0c\u8ab2\u984c\u306f\u89e3\u6c7a\u5bfe\u8c61(\u30d1\u30ba\u30eb\u3068\u304b)\u3092\u4e0e\u3048\u3089\u308c\u3066\uff0c\u554f\u984c\u5b9a\u7fa9\u3068\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0(\u6307\u5b9a\u8a00\u8a9e\u306fC++\u3082\u3057\u304f\u306fJava)\u3068\u3044\u3046\u3044\u308f\u3070\u666e\u901a\u306a\u8ab2\u984c\u3067\u306f\u3042\u308b\u3093\u3060\u3051\u3069\uff0e\u95a2\u6570\u578b\u8a00\u8a9e\u306fHaskell\u306e\u6388\u696d\u304c\u307e\u305f\u5225\u306b\u3042\u308b\u306e\uff0e","id":30078427155406848,"from_user_id":2331498,"to_user":"kami_joe","geo":null,"iso_language_code":"ja","to_user_id_str":"79273052","source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"79151233","profile_image_url":"http://a2.twimg.com/a/1295051201/images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 01:40:37 +0000","from_user":"cz_newdrafts","id_str":"30077617361125376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell programming language http://bit.ly/gpPAwB","id":30077617361125376,"from_user_id":79151233,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://tommorris.org/" rel="nofollow">tommorris' hacksample</a>"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:57 +0000","from_user":"Verus","id_str":"30068139416879104","metadata":{"result_type":"recent"},"to_user_id":9252720,"text":"@shukukei Java\u3068C\u306f\u3042\u308b\u7a0b\u5ea6\u66f8\u3051\u3066\u3042\u305f\u308a\u307e\u3048\u306a\u3068\u3053\u308d\u304c\u3042\u308b\u304b\u3089\u306a\u30fc\uff0ePython\u306f\u500b\u4eba\u7684\u306b\u611f\u899a\u304c\u5408\u308f\u306a\u3044\uff0e\u611f\u899a\u306a\u306e\u3067\uff0c\u3082\u3046\u3069\u3046\u3057\u3088\u3046\u3082\u306a\u3044\uff57 \u3044\u307e\u306fScala\u3068Haskell\u3092\u3082\u3063\u3068\u6975\u3081\u305f\u3044\u3068\u3053\u308d\uff0e","id":30068139416879104,"from_user_id":2331498,"to_user":"shukukei","geo":null,"iso_language_code":"ja","to_user_id_str":"9252720","source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"2781460","profile_image_url":"http://a0.twimg.com/profile_images/82526625/.joeyicon_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:35 +0000","from_user":"joeyhess","id_str":"30068046538219520","metadata":{"result_type":"recent"},"to_user_id":null,"text":"just figured out that I can use parameterized types to remove a dependency loop in git-annex's type definitions. whee #haskell","id":30068046538219520,"from_user_id":2781460,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://identi.ca" rel="nofollow">identica</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 00:54:22 +0000","from_user":"listwarenet","id_str":"30065977920061440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84466-haskell-beginners-bytestring-question.html Haskell-beginners - Bytestrin","id":30065977920061440,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"1291845","profile_image_url":"http://a0.twimg.com/profile_images/1225743404/ThinOxygen-small-opaque-solidarity_normal.png","created_at":"Wed, 26 Jan 2011 00:52:07 +0000","from_user":"_aaron_","id_str":"30065412242669568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"wanted: librly licensed high level native compiled lang with min runtime (otherwise cobra/mono would be perfect) for win. lua? haskell? ooc?","id":30065412242669568,"from_user_id":1291845,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"}],"max_id":30120402839666689,"since_id":0,"refresh_url":"?since_id=30120402839666689&q=haskell","next_page":"?page=2&max_id=30120402839666689&rpp=50&q=haskell","results_per_page":50,"page":1,"completed_in":0.291696,"since_id_str":"0","max_id_str":"30120402839666689","query":"haskell"}+{"results":[{"from_user_id_str":"207858021","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 04:30:38 +0000","from_user":"pboudarga","id_str":"30120402839666689","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Rolla Sushi Grill (27737 Bouquet Canyon Road, #106, Btw Haskell Canyon and Rosedell Drive, Saugus) http://4sq.com/gqqdhs","id":30120402839666689,"from_user_id":207858021,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"69988683","profile_image_url":"http://a0.twimg.com/profile_images/1211955817/avatar_7888_normal.gif","created_at":"Wed, 26 Jan 2011 04:25:23 +0000","from_user":"YNK33","id_str":"30119083059978240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"hsndfile 0.5.0: Free and open source Haskell bindings for libsndfile http://bit.ly/gHaBWG Mac Os","id":30119083059978240,"from_user_id":69988683,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"81492","profile_image_url":"http://a1.twimg.com/profile_images/423894208/Picture_7_normal.jpg","created_at":"Wed, 26 Jan 2011 04:24:28 +0000","from_user":"satzz","id_str":"30118851488251904","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Emacs\u306e\u30e2\u30fc\u30c9\u8868\u793a\u304c\u4eca(Ruby Controller Outputz RoR Flymake REl hs)\u3068\u306a\u3063\u3066\u3066\u3088\u304f\u308f\u304b\u3089\u306a\u3044\u3093\u3060\u3051\u3069\u6700\u5f8c\u306eREl\u3068\u304bhs\u3063\u3066\u4f55\u3060\u308d\u3046\u2026haskell\u3068\u304b2\u5e74\u4ee5\u4e0a\u66f8\u3044\u3066\u306a\u3044\u3051\u3069\u2026","id":30118851488251904,"from_user_id":81492,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"9518356","profile_image_url":"http://a2.twimg.com/profile_images/119165723/ocaml-icon_normal.png","created_at":"Wed, 26 Jan 2011 04:19:19 +0000","from_user":"planet_ocaml","id_str":"30117557788741632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I so miss #haskell type classes in #ocaml - i want to do something like refinement. Also why does ocaml not have... http://bit.ly/geYRwt","id":30117557788741632,"from_user_id":9518356,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"218059","profile_image_url":"http://a1.twimg.com/profile_images/1053837723/twitter-icon9_normal.jpg","created_at":"Wed, 26 Jan 2011 04:16:32 +0000","from_user":"aprikip","id_str":"30116854940835840","metadata":{"result_type":"recent"},"to_user_id":null,"text":"yatex-mode\u3084haskell-mode\u306e\u3053\u3068\u3067\u3059\u306d\u3001\u308f\u304b\u308a\u307e\u3059\u3002","id":30116854940835840,"from_user_id":218059,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sites.google.com/site/yorufukurou/" rel="nofollow">YoruFukurou</a>"},{"from_user_id_str":"216363","profile_image_url":"http://a1.twimg.com/profile_images/72454310/Tim-Avatar_normal.png","created_at":"Wed, 26 Jan 2011 04:15:30 +0000","from_user":"dysinger","id_str":"30116594684264448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell in Hawaii tonight for me... #fun","id":30116594684264448,"from_user_id":216363,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.nambu.com/" rel="nofollow">Nambu</a>"},{"from_user_id_str":"1774820","profile_image_url":"http://a2.twimg.com/profile_images/61169291/dan_desert_thumb_normal.jpg","created_at":"Wed, 26 Jan 2011 04:13:36 +0000","from_user":"DanMil","id_str":"30116117682851840","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire @tomheon Haskell isn't a language, it's a belief system. A seductive one...","id":30116117682851840,"from_user_id":1774820,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"659256","profile_image_url":"http://a0.twimg.com/profile_images/746976711/angular-final_normal.jpg","created_at":"Wed, 26 Jan 2011 04:11:06 +0000","from_user":"djspiewak","id_str":"30115488931520512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"One of the very nice things about Haskell as opposed to SML is the reduced proliferation of identifiers (e.g. andb, orb, etc). #typeclasses","id":30115488931520512,"from_user_id":659256,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 04:06:12 +0000","from_user":"listwarenet","id_str":"30114255890026496","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84752-re-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Re: Haskell-c","id":30114255890026496,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 04:01:29 +0000","from_user":"ojrac","id_str":"30113067333324800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tomheon: @ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30113067333324800,"from_user_id":1594784,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"207589736","profile_image_url":"http://a3.twimg.com/profile_images/1225527428/headshot_1_normal.jpg","created_at":"Wed, 26 Jan 2011 04:00:13 +0000","from_user":"ashleevelazq101","id_str":"30112747555397632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/dONnpn","id":30112747555397632,"from_user_id":207589736,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"Hackage","id_str":"30112192346984448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112192346984448,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"aapnoot","id_str":"30112191881420800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112191881420800,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"8530482","profile_image_url":"http://a2.twimg.com/profile_images/137867266/n608671563_7396_normal.jpg","created_at":"Wed, 26 Jan 2011 03:50:12 +0000","from_user":"jeffmclamb","id_str":"30110229207187456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Angel - daemon to run and monitor processes like daemontools or god, written in Haskell http://ff.im/-wNyLk","id":30110229207187456,"from_user_id":8530482,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://friendfeed.com" rel="nofollow">FriendFeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:46:01 +0000","from_user":"tomheon","id_str":"30109174645919744","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30109174645919744,"from_user_id":177539201,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 03:44:34 +0000","from_user":"ojrac","id_str":"30108808684503040","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire @tomheon Why are you making me curious about Haskell? I LIKE not knowing what monad means!!","id":30108808684503040,"from_user_id":1594784,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"23750094","profile_image_url":"http://a0.twimg.com/profile_images/951373780/Moeinthecar_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:54 +0000","from_user":"shokalshab","id_str":"30108140443795456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Magnitude Cheer @ Gymnastics Olympica USA (7735 Haskell Ave., btw Saticoy & Strathern, Van Nuys) http://4sq.com/gmXfaL","id":30108140443795456,"from_user_id":23750094,"geo":null,"iso_language_code":"en","place":{"id":"4e4a2a2f86cb2946","type_":"poi","full_name":"Gymnastics Olympica USA, Van Nuys"},"to_user_id_str":null,"source":"<a href="http://foursquare.com" rel="nofollow">foursquare</a>"},{"from_user_id_str":"8135112","profile_image_url":"http://a0.twimg.com/profile_images/1165240350/LIMITED_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:35 +0000","from_user":"Claricei","id_str":"30108059208515584","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @kristenmchugh22: @KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30108059208515584,"from_user_id":8135112,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:40:02 +0000","from_user":"chewedwire","id_str":"30107670367182848","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon Cool, I'll take a look. I feel like I should mention this: http://bit.ly/hVstDM","id":30107670367182848,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"8679778","profile_image_url":"http://a3.twimg.com/profile_images/1195318056/me_nyc_12_18_10_icon_normal.jpg","created_at":"Wed, 26 Jan 2011 03:38:42 +0000","from_user":"kristenmchugh22","id_str":"30107332381777920","metadata":{"result_type":"recent"},"to_user_id":756269,"text":"@KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30107332381777920,"from_user_id":8679778,"to_user":"KeithOlbermann","geo":null,"iso_language_code":"en","to_user_id_str":"756269","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"103316559","profile_image_url":"http://a1.twimg.com/profile_images/1179458751/bc3beab4-d59d-4e78-b13b-50747986cfa2_normal.png","created_at":"Wed, 26 Jan 2011 03:36:15 +0000","from_user":"cityslikr","id_str":"30106719153557504","metadata":{"result_type":"recent"},"to_user_id":null,"text":""Social safety net into a hammock." So says Eddie Haskell with the GOP response. #SOTU","id":30106719153557504,"from_user_id":103316559,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry\u00ae</a>"},{"from_user_id_str":"169063143","profile_image_url":"http://a0.twimg.com/profile_images/1160506212/9697_1_normal.gif","created_at":"Wed, 26 Jan 2011 03:31:52 +0000","from_user":"wrkforce_safety","id_str":"30105614919143424","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/gA60C1","id":30105614919143424,"from_user_id":169063143,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:29:40 +0000","from_user":"tomheon","id_str":"30105060960632832","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire Great book on Haskell: http://oreilly.com/catalog/9780596514983","id":30105060960632832,"from_user_id":177539201,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"782692","profile_image_url":"http://a0.twimg.com/profile_images/1031304589/Profile.2007.1_normal.jpg","created_at":"Wed, 26 Jan 2011 03:29:19 +0000","from_user":"turnageb","id_str":"30104974591533057","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @ovillalon: Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104974591533057,"from_user_id":782692,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:28:04 +0000","from_user":"chewedwire","id_str":"30104657267265536","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon I always loved the pattern matching in SML and it looks like Haskell is MUCH better at it. I'm messing around now at tryhaskell.org","id":30104657267265536,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"12834082","profile_image_url":"http://a3.twimg.com/profile_images/1083036140/mugshot_normal.png","created_at":"Wed, 26 Jan 2011 03:28:01 +0000","from_user":"ovillalon","id_str":"30104647213518848","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104647213518848,"from_user_id":12834082,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:26:02 +0000","from_user":"goodfox","id_str":"30104146455560192","metadata":{"result_type":"recent"},"to_user_id":10226179,"text":"@billykeene22 Bordeaux is one of my heroes. I was so excited when he accepted the invitation to campus. He's been a great friend to Haskell.","id":30104146455560192,"from_user_id":13540930,"to_user":"billykeene22","geo":null,"iso_language_code":"en","to_user_id_str":"10226179","source":"<a href="http://www.ubertwitter.com/bb/download.php" rel="nofollow">\u00dcberTwitter</a>"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 03:25:18 +0000","from_user":"josej30","id_str":"30103962313031681","metadata":{"result_type":"recent"},"to_user_id":14870909,"text":"@cris7ian Ahh bueno multiparadigma ya es respetable :) Empezar\u00e9 a explotar la parte funcional de los lenguajes ahora #Haskell","id":30103962313031681,"from_user_id":18616016,"to_user":"Cris7ian","geo":null,"iso_language_code":"es","to_user_id_str":"14870909","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"14870909","profile_image_url":"http://a2.twimg.com/profile_images/1176930429/oso_yo_normal.png","created_at":"Wed, 26 Jan 2011 03:23:43 +0000","from_user":"Cris7ian","id_str":"30103562360983553","metadata":{"result_type":"recent"},"to_user_id":18616016,"text":"@josej30 hahaha no, es multiparadigma y es bastante lazy. Nothing like haskell, pero s\u00ed, el de Flash","id":30103562360983553,"from_user_id":14870909,"to_user":"josej30","geo":null,"iso_language_code":"es","to_user_id_str":"18616016","source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"2421643","profile_image_url":"http://a0.twimg.com/profile_images/1190361665/ernestgrumbles-17_normal.jpg","created_at":"Wed, 26 Jan 2011 03:20:24 +0000","from_user":"ernestgrumbles","id_str":"30102730756333568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Wow... WolframAlpha did not know who Eddie Haskell is. Guess I'll never use that "knowledge engine" again.","id":30102730756333568,"from_user_id":2421643,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:14:21 +0000","from_user":"chewedwire","id_str":"30101204428132352","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon How is Haskell better/different from CL or Scheme? I honestly don't know, although I'm becoming more curious.","id":30101204428132352,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:06:54 +0000","from_user":"goodfox","id_str":"30099329809129473","metadata":{"result_type":"recent"},"to_user_id":null,"text":"A day of vision & speeches. #SOTU now. And a wonderful Haskell Convocation address earlier today by Sinte Gleske President Lionel Bordeaux.","id":30099329809129473,"from_user_id":13540930,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.ubertwitter.com/bb/download.php" rel="nofollow">\u00dcberTwitter</a>"},{"from_user_id_str":"119185220","profile_image_url":"http://a0.twimg.com/profile_images/1089027228/dfg_normal.jpg","created_at":"Wed, 26 Jan 2011 03:03:38 +0000","from_user":"LaLiciouz_03","id_str":"30098510623805440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"The Game with the girl room 330 Haskell follow us...","id":30098510623805440,"from_user_id":119185220,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 02:57:25 +0000","from_user":"josej30","id_str":"30096946144215040","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Voy a extra\u00f1ar Haskell cuando regrese al mundo imperativo. Hay alg\u00fan lenguaje imperativo que tenga este poder funcional? #ci3661","id":30096946144215040,"from_user_id":18616016,"geo":null,"iso_language_code":"es","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 02:55:32 +0000","from_user":"Hackage","id_str":"30096471814574080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"comonad-transformers 0.9.0, added by EdwardKmett: Haskell 98 comonad transformers http://bit.ly/h6xIsf","id":30096471814574080,"from_user_id":17671137,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 02:48:12 +0000","from_user":"tomheon","id_str":"30094626920603649","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Every time I look at Haskell I love it more.","id":30094626920603649,"from_user_id":177539201,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"60792568","profile_image_url":"http://a0.twimg.com/profile_images/1203647517/glenda-flash_normal.jpg","created_at":"Wed, 26 Jan 2011 02:40:42 +0000","from_user":"r_takaishi","id_str":"30092735935422464","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u3088\u308aD\u8a00\u8a9e\u304c\u4e0a\u3068\u306f\u601d\u308f\u306a\u304b\u3063\u305f\uff0e http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html","id":30092735935422464,"from_user_id":60792568,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twmode.sf.net/" rel="nofollow">twmode</a>"},{"from_user_id_str":"160145510","profile_image_url":"http://a0.twimg.com/profile_images/1218108166/going_galt_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:31 +0000","from_user":"wtp1787","id_str":"30092439653974018","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @KLSouth: Eddie Haskell Goes to Washington... "You look really nice tonight, Ms Cleaver"","id":30092439653974018,"from_user_id":160145510,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"96616016","profile_image_url":"http://a1.twimg.com/profile_images/1196978169/Picture0002_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:20 +0000","from_user":"MelissaRNMBA","id_str":"30092392203816960","metadata":{"result_type":"recent"},"to_user_id":14862975,"text":"@KLSouth At least Eddie Haskell was entertaining.","id":30092392203816960,"from_user_id":96616016,"to_user":"KLSouth","geo":null,"iso_language_code":"en","to_user_id_str":"14862975","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"14862975","profile_image_url":"http://a0.twimg.com/profile_images/421596393/kls_4_normal.JPG","created_at":"Wed, 26 Jan 2011 02:38:29 +0000","from_user":"KLSouth","id_str":"30092178327871489","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Eddie Haskell Goes to Washington... "You look really nice tonight, Ms Cleaver"","id":30092178327871489,"from_user_id":14862975,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 02:36:17 +0000","from_user":"listwarenet","id_str":"30091626869161984","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84641-haskell-beginners-wildcards-in-expressions.html Haskell-beginners - Wild","id":30091626869161984,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"24538048","profile_image_url":"http://a2.twimg.com/profile_images/1117267605/rope_normal.jpg","created_at":"Wed, 26 Jan 2011 02:23:14 +0000","from_user":"dbph","id_str":"30088341030440960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @dnene: Skilled Calisthenics. Haskell code that outputs python which spits ruby which emits the haskell source. http://j.mp/YlQUL via @mfeathers","id":30088341030440960,"from_user_id":24538048,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:58:31 +0000","from_user":"YubaVetTech","id_str":"30082124207886336","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigious Hayward Award for \u2018Excellence in Education\u2019. This award honors... http://fb.me/QgQCxd74","id":30082124207886336,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:56:04 +0000","from_user":"YubaVetTech","id_str":"30081505476743168","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigous Haward Award for Excellence in Education. This award honors... http://fb.me/PC9mYmCR","id":30081505476743168,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://www.facebook.com/twitter" rel="nofollow">Facebook</a>"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:43:50 +0000","from_user":"Verus","id_str":"30078427155406848","metadata":{"result_type":"recent"},"to_user_id":79273052,"text":"@kami_joe \u3044\u3084\uff0c\u8ab2\u984c\u306f\u89e3\u6c7a\u5bfe\u8c61(\u30d1\u30ba\u30eb\u3068\u304b)\u3092\u4e0e\u3048\u3089\u308c\u3066\uff0c\u554f\u984c\u5b9a\u7fa9\u3068\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0(\u6307\u5b9a\u8a00\u8a9e\u306fC++\u3082\u3057\u304f\u306fJava)\u3068\u3044\u3046\u3044\u308f\u3070\u666e\u901a\u306a\u8ab2\u984c\u3067\u306f\u3042\u308b\u3093\u3060\u3051\u3069\uff0e\u95a2\u6570\u578b\u8a00\u8a9e\u306fHaskell\u306e\u6388\u696d\u304c\u307e\u305f\u5225\u306b\u3042\u308b\u306e\uff0e","id":30078427155406848,"from_user_id":2331498,"to_user":"kami_joe","geo":null,"iso_language_code":"ja","to_user_id_str":"79273052","source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"79151233","profile_image_url":"http://a2.twimg.com/a/1295051201/images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 01:40:37 +0000","from_user":"cz_newdrafts","id_str":"30077617361125376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell programming language http://bit.ly/gpPAwB","id":30077617361125376,"from_user_id":79151233,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://tommorris.org/" rel="nofollow">tommorris' hacksample</a>"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:57 +0000","from_user":"Verus","id_str":"30068139416879104","metadata":{"result_type":"recent"},"to_user_id":9252720,"text":"@shukukei Java\u3068C\u306f\u3042\u308b\u7a0b\u5ea6\u66f8\u3051\u3066\u3042\u305f\u308a\u307e\u3048\u306a\u3068\u3053\u308d\u304c\u3042\u308b\u304b\u3089\u306a\u30fc\uff0ePython\u306f\u500b\u4eba\u7684\u306b\u611f\u899a\u304c\u5408\u308f\u306a\u3044\uff0e\u611f\u899a\u306a\u306e\u3067\uff0c\u3082\u3046\u3069\u3046\u3057\u3088\u3046\u3082\u306a\u3044\uff57 \u3044\u307e\u306fScala\u3068Haskell\u3092\u3082\u3063\u3068\u6975\u3081\u305f\u3044\u3068\u3053\u308d\uff0e","id":30068139416879104,"from_user_id":2331498,"to_user":"shukukei","geo":null,"iso_language_code":"ja","to_user_id_str":"9252720","source":"<a href="http://itunes.apple.com/us/app/twitter/id409789998?mt=12" rel="nofollow">Twitter for Mac</a>"},{"from_user_id_str":"2781460","profile_image_url":"http://a0.twimg.com/profile_images/82526625/.joeyicon_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:35 +0000","from_user":"joeyhess","id_str":"30068046538219520","metadata":{"result_type":"recent"},"to_user_id":null,"text":"just figured out that I can use parameterized types to remove a dependency loop in git-annex's type definitions. whee #haskell","id":30068046538219520,"from_user_id":2781460,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://identi.ca" rel="nofollow">identica</a>"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 00:54:22 +0000","from_user":"listwarenet","id_str":"30065977920061440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84466-haskell-beginners-bytestring-question.html Haskell-beginners - Bytestrin","id":30065977920061440,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"<a href="http://1e10.org/cloud/" rel="nofollow">1e10</a>"},{"from_user_id_str":"1291845","profile_image_url":"http://a0.twimg.com/profile_images/1225743404/ThinOxygen-small-opaque-solidarity_normal.png","created_at":"Wed, 26 Jan 2011 00:52:07 +0000","from_user":"_aaron_","id_str":"30065412242669568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"wanted: librly licensed high level native compiled lang with min runtime (otherwise cobra/mono would be perfect) for win. lua? haskell? ooc?","id":30065412242669568,"from_user_id":1291845,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"}],"max_id":30120402839666689,"since_id":0,"refresh_url":"?since_id=30120402839666689&q=haskell","next_page":"?page=2&max_id=30120402839666689&rpp=50&q=haskell","results_per_page":50,"page":1,"completed_in":0.291696,"since_id_str":"0","max_id_str":"30120402839666689","query":"haskell"}
changelog.md view
@@ -1,23 +1,104 @@-0.9.0.1+# 0.10.0.0 -* A stray export of encodeToBuilder got away!+## Performance improvements -0.9.0.0+* Direct encoding via the new `toEncoding` method is over 2x faster+ than `toJSON`. (You must write or code-gen a `toEncoding`+ implementation to unlock this speedup. See below for details.) -* The json and json' parsers are now synonyms for value and value', in- conformance with the looser semantics of RFC 7159.+* Improved string decoding gives a 12% speed win in parsing+ string-heavy JSON payloads (very common). -* Renamed encodeToByteStringBuilder to the more compact- encodeToBuilder.+* Encoding and decoding of time-related types are 10x faster (!!) as a+ result of bypassing `Data.Time.Format` and the arbitrary-precision+ `Integer` type. -0.8.1.1+* When using `toEncoding`, `[Char]` can be encoded without a conversion to+ `Text`. This is fast and efficient. -* The dependency on the unordered-containers package was too lax, and- has been corrected.+* Parsing into an `Object` is now 5% faster and more+ allocation-efficient. -0.8.1.0+## SUBTLE API CHANGES, READ CAREFULLY -* Encoding a Scientific value with a huge exponent is now handled+With the exception of long-deprecated code, the API changes below+**should be upwards compatible** from older versions of `aeson`. If you run+into upgrade problems, please file an issue with details.++* The `ToJSON` class has a new method, `toEncoding`, that allows+ direct encoding from a Haskell value to a lazy bytestring without+ construction of an intermediate `Value`.++ The performance benefits of direct encoding are significant: more+ than 2x faster than before, with less than 1/3 the memory usage.++ To preserve API compatibility across upgrades from older versions of+ this library, the default implementation of `toEncoding` uses+ `toJSON`. You will *not* see any performance improvement unless you+ write an implementation of `toEncoding`, which can be very simple:++ ```haskell+ instance ToJSON Coord where+ toEncoding = genericToEncoding defaultOptions+ ```++ (Behind the scenes, the `encode` function uses `toEncoding` now, so+ if you implement `toEncoding` for your types, you should see a+ speedup immediately.)++ If you use Template Haskell or GHC Generics to auto-generate your+ `ToJSON` instances, you'll benefit from fast toEncoding+ implementations for free!++* When converting from a `Value` to a target Haskell type, `FromJSON`+ instances now provide much better error messages, including a+ complete JSON path from the root of the object to the offending+ element. This greatly eases debugging.++* It is now possible to use Template Haskell to generate `FromJSON`+ and `ToJSON` instances for types in data families.++* If you use Template Haskell or generics, and used to use the+ `camelTo` function to rename fields, the new `camelTo2` function is+ smarter. For example, `camelTo` will rename `CamelAPICase` to+ `camelapi_case` (ugh!), while `camelTo2` will map it to+ `camel_api_case` (yay!).++* New `ToJSON` and `FromJSON` instances for the following time-related+ types: `Day`, `LocalTime`.++* The `Result` type is now an instance of `Foldable` and `Traversable`.++* The `Data.Aeson.Generic` module has been removed. It was deprecated in+ late 2013.++* GHC 7.2 and older are no longer supported.++* The instance of `Monad` for the `Result` type lacked an implementation+ of `fail` (oops). This has been corrected.++++# 0.9.0.1++* A stray export of `encodeToBuilder` got away!++# 0.9.0.0++* The `json` and `json'` parsers are now synonyms for `value` and+ `value'`, in conformance with the looser semantics of RFC 7159.++* Renamed `encodeToByteStringBuilder` to the more compact+ `encodeToBuilder`.++# 0.8.1.1++* The dependency on the `unordered-containers` package was too lax,+ and has been corrected.++# 0.8.1.0++* Encoding a `Scientific` value with a huge exponent is now handled efficiently. (This would previously allocate a huge arbitrary-precision integer, potentially leading to a denial of service.)@@ -27,55 +108,56 @@ megabyte of consecutive backslashes, the new implementation is 27x faster and uses 42x less memory. -* The ToJSON instance for UTCTime is rendered with higher (picosecond)- resolution.+* The `ToJSON` instance for `UTCTime` is rendered with higher+ (picosecond) resolution. -* The value parser now correctly handles leading whitespace.+* The `value` parser now correctly handles leading whitespace. -* New instances of ToJSON and FromJSON for Data.Sequence and- Data.Functor.Identity. The Value type now has a Read instance.+* New instances of `ToJSON` and `FromJSON` for `Data.Sequence` and+ `Data.Functor.Identity`. The `Value` type now has a `Read` instance. -* ZonedTime parser ordering now favours the standard JSON format,+* `ZonedTime` parser ordering now favours the standard `JSON` format, increasing efficiency in the common case. -* Encoding to a Text.Builder now escapes '<' and '>' characters, to- reduce XSS risk.+* Encoding to a `Text.Builder` now escapes `'<'` and `'>'` characters,+ to reduce XSS risk. -0.8.0.2+# 0.8.0.2 -* Fix ToJSON instance for 15-tuples (see #223).+* Fix `ToJSON` instance for 15-tuples (see #223). -0.8.0.1+# 0.8.0.1 -* Support time-1.5.+* Support `time-1.5`. -0.8.0.0+# 0.8.0.0 -* Add ToJSON and FromJSON instances for tuples of up to 15 elements.+* Add `ToJSON` and `FromJSON` instances for tuples of up to 15+ elements. -0.7.1.0+# 0.7.1.0 * Major compiler and library compatibility changes: we have dropped- support for GHC older than 7.4, text older than 1.1, and bytestring- older than 0.10.4.0. Supporting the older versions had become- increasingly difficult, to the point where it was no longer worth- it.+ support for GHC older than 7.4, `text` older than 1.1, and+ `bytestring` older than 0.10.4.0. Supporting the older versions had+ become increasingly difficult, to the point where it was no longer+ worth it. -0.7.0.0+# 0.7.0.0 * The performance of encoding to and decoding of bytestrings have both improved by up to 2x, while also using less memory. -* New dependency: the scientific package lets us parse floating point+* New dependency: the `scientific` package lets us parse floating point numbers more quickly and accurately. -* eitherDecode, decodeStrictWith: fixed bugs.+* `eitherDecode`, `decodeStrictWith`: fixed bugs. -* Added FromJSON and ToJSON instances for Tree and Scientific.+* Added `FromJSON` and `ToJSON` instances for `Tree` and `Scientific`. -* Fixed the ToJSON instances for UTCTime and ZonedTime.+* Fixed the `ToJSON` instances for `UTCTime` and `ZonedTime`. -0.6 series+# 0.6 series * Much improved documentation. @@ -85,44 +167,44 @@ * Fixed up handling of nullary constructors when using generic encoding. -* Added ToJSON/FromJSON instances for:+* Added `ToJSON`/`FromJSON` instances for: - * The Fixed class- * ISO-8601 dates: UTCTime, ZonedTime, and TimeZone+ * The `Fixed` class+ * ISO-8601 dates: `UTCTime`, `ZonedTime`, and `TimeZone` -* Added accessor functions for inspecting Values.+* Added accessor functions for inspecting `Value`s. -* Added eitherDecode function that returns an error message if+* Added `eitherDecode` function that returns an error message if decoding fails. -0.5 to 0.6+# 0.5 to 0.6 * This release introduces a slightly obscure, but backwards-incompatible, change. In the generic APIs of versions 0.4 and 0.5, fields whose names- began with a "_" character would have this character removed. This+ began with a `"_"` character would have this character removed. This no longer occurs, as it was both buggy and surprising (https://github.com/bos/aeson/issues/53). * Fixed a bug in generic decoding of nullary constructors (https://github.com/bos/aeson/issues/62). -0.4 to 0.5+# 0.4 to 0.5 * When used with the UTF-8 encoding performance improvements- introduced in version 0.11.1.12 of the text package, this release- improves aeson's JSON encoding performance by 33% relative to aeson- 0.4.+ introduced in version 0.11.1.12 of the `text` package, this release+ improves `aeson`'s JSON encoding performance by 33% relative to+ `aeson` 0.4. As part of achieving this improvement, an API change was necessary.- The fromValue function in the Data.Aeson.Encode module now uses the- text package's Builder type instead of the blaze-builder package's- Builder type.+ The `fromValue` function in the `Data.Aeson.Encode` module now uses+ the `text` package's `Builder` type instead of the `blaze-builder`+ package's `Builder` type. -0.3 to 0.4+# 0.3 to 0.4 -* The new decode function complements the longstanding encode+* The new `decode` function complements the longstanding `encode` function, and makes the API simpler. * New examples make it easier to learn to use the package@@ -130,12 +212,12 @@ * Generics support - aeson's support for data-type generic programming makes it possible- to use JSON encodings of most data types without writing any- boilerplate instances.+ `aeson`'s support for data-type generic programming makes it+ possible to use JSON encodings of most data types without writing+ any boilerplate instances. - Thanks to Bas Van Dijk, aeson now supports the two major schemes for- doing datatype-generic programming:+ Thanks to Bas Van Dijk, `aeson` now supports the two major schemes+ for doing datatype-generic programming: * the modern mechanism, built into GHC itself (http://www.haskell.org/ghc/docs/latest/html/users_guide/generic-programming.html)@@ -145,32 +227,32 @@ The modern GHC-based generic mechanism is fast and terse: in fact, its performance is generally comparable in performance to- hand-written and TH-derived ToJSON and FromJSON instances. To see- how to use GHC generics, refer to examples/Generic.hs.+ hand-written and TH-derived `ToJSON` and `FromJSON` instances. To+ see how to use GHC generics, refer to `examples/Generic.hs`. - The SYB-based generics support lives in Data.Aeson.Generic and is+ The SYB-based generics support lives in `Data.Aeson.Generic` and is provided mainly for users of GHC older than 7.2. SYB is far slower (by about 10x) than the more modern generic mechanism. To see how- to use SYB generics, refer to examples/GenericSYB.hs.+ to use SYB generics, refer to `examples/GenericSYB.hs`. * We switched the intermediate representation of JSON objects from- Data.Map to Data.HashMap which has improved type conversion+ `Data.Map` to `Data.HashMap` which has improved type conversion performance. -* Instances of ToJSON and FromJSON for tuples are between 45% and 70%+* Instances of `ToJSON` and `FromJSON` for tuples are between 45% and 70% faster than in 0.3. * Evaluation control This version of aeson makes explicit the decoupling between *identifying* an element of a JSON document and *converting* it to- Haskell. See the Data.Aeson.Parser documentation for details.+ Haskell. See the `Data.Aeson.Parser` documentation for details. - The normal aeson decode function performs identification strictly,- but defers conversion until needed. This can result in improved- performance (e.g. if the results of some conversions are never- needed), but at a cost in increased memory consumption.+ The normal `aeson` `decode` function performs identification+ strictly, but defers conversion until needed. This can result in+ improved performance (e.g. if the results of some conversions are+ never needed), but at a cost in increased memory consumption. - The new decode' function performs identification and conversion+ The new `decode'` function performs identification and conversion immediately. This incurs an up-front cost in CPU cycles, but reduces reduce memory consumption.
examples/Generic.hs view
@@ -2,9 +2,6 @@ -- GHC's builtin generics instead of explicit instances of ToJSON and -- FromJSON. --- This example only works with GHC 7.2 or newer, as it uses the--- datatype-generic programming machinery introduced in 7.2.- -- We enable the DeriveGeneric language extension so that GHC can -- automatically derive the Generic class for us.
− examples/GenericSYB.hs
@@ -1,30 +0,0 @@--- This example is basically the same as in Simplest.hs, only it uses--- SYB generics instead of explicit instances of ToJSON and FromJSON.---- This mechanism is much slower than the newer generics mechanism--- demonstrated in Generic.hs, but it works on versions of GHC older--- than 7.2.---- We enable the DeriveDataTypeable language extension so that GHC can--- automatically derive the Typeable and Data classes for us.--{-# LANGUAGE DeriveDataTypeable #-}--{-# LANGUAGE OverloadedStrings #-}--import Data.Data (Typeable, Data)-import Data.Aeson.Generic (decode, encode)-import qualified Data.ByteString.Lazy.Char8 as BL---- To decode or encode a value using the generic machinery, we must--- make the type an instance of the Typeable and Data classes.--data Coord = Coord { x :: Double, y :: Double }- deriving (Show, Typeable, Data)--main :: IO ()-main = do- let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord- print req- let reply = Coord 123.4 20- BL.putStrLn (encode reply)
examples/Simplest.hs view
@@ -1,7 +1,8 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings, RecordWildCards #-} import Control.Applicative ((<$>), (<*>), empty) import Data.Aeson+import Data.Monoid import qualified Data.ByteString.Lazy.Char8 as BL data Coord = Coord { x :: Double, y :: Double }@@ -12,6 +13,10 @@ instance ToJSON Coord where toJSON (Coord xV yV) = object [ "x" .= xV, "y" .= yV ]++ toEncoding Coord{..} = pairs $+ "x" .= x <>+ "y" .= y -- A FromJSON instance allows us to decode a value from JSON. This -- should match the format used by the ToJSON instance.
+ examples/Twitter.hs view
@@ -0,0 +1,74 @@+-- These types follow the format of Twitter search results, as can be+-- found in the benchmarks/json-data directory.+--+-- For uses of these types, see the Twitter subdirectory.+--+-- There is one deviation for the sake of convenience: the Geo field+-- named "type_" is really named "type" in Twitter's real feed. I+-- renamed "type" to "type_" in the *.json files, to avoid overlap+-- with a Haskell reserved keyword.++{-# LANGUAGE DeriveDataTypeable, DeriveGeneric #-}++module Twitter (+ Metadata(..)+ , Geo(..)+ , Story(..)+ , Result(..)+ ) where++import Data.Data (Typeable, Data)+import Data.Int (Int64)+import Data.Text (Text)+-- import Data.Time (ZonedTime)+import GHC.Generics (Generic)+import Prelude hiding (id)+import Control.DeepSeq++data Metadata = Metadata {+ result_type :: Text+ } deriving (Eq, Show, Typeable, Data, Generic)++instance NFData Metadata++data Geo = Geo {+ type_ :: Text+ , coordinates :: (Double, Double)+ } deriving (Eq, Show, Typeable, Data, Generic)++instance NFData Geo++data Story = Story {+ from_user_id_str :: Text+ , profile_image_url :: Text+ , created_at :: Text -- ZonedTime+ , from_user :: Text+ , id_str :: Text+ , metadata :: Metadata+ , to_user_id :: Maybe Int64+ , text :: Text+ , id :: Int64+ , from_user_id :: Int64+ , geo :: Maybe Geo+ , iso_language_code :: Text+ , to_user_id_str :: Maybe Text+ , source :: Text+ } deriving (Show, Typeable, Data, Generic)++instance NFData Story++data Result = Result {+ results :: [Story]+ , max_id :: Int64+ , since_id :: Int64+ , refresh_url :: Text+ , next_page :: Text+ , results_per_page :: Int+ , page :: Int+ , completed_in :: Double+ , since_id_str :: Text+ , max_id_str :: Text+ , query :: Text+ } deriving (Show, Typeable, Data, Generic)++instance NFData Result
+ examples/Twitter/Generic.hs view
@@ -0,0 +1,26 @@+-- Use GHC generics to automatically generate good instances.++{-# OPTIONS_GHC -fno-warn-orphans #-}++module Twitter.Generic+ (+ Metadata(..)+ , Geo(..)+ , Story(..)+ , Result(..)+ ) where++import Data.Aeson (ToJSON, FromJSON)+import Twitter++instance ToJSON Metadata+instance FromJSON Metadata++instance ToJSON Geo+instance FromJSON Geo++instance ToJSON Story+instance FromJSON Story++instance ToJSON Result+instance FromJSON Result
+ examples/Twitter/Manual.hs view
@@ -0,0 +1,141 @@+-- Manually write instances.++{-# LANGUAGE OverloadedStrings, RecordWildCards #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Twitter.Manual+ (+ Metadata(..)+ , Geo(..)+ , Story(..)+ , Result(..)+ ) where++import Control.Applicative+import Data.Aeson hiding (Result)+import Data.Monoid ((<>))+import Prelude hiding (id)+import Twitter++instance ToJSON Metadata where+ toJSON Metadata{..} = object [+ "result_type" .= result_type+ ]++ toEncoding Metadata{..} = pairs $+ "result_type" .= result_type++instance FromJSON Metadata where+ parseJSON (Object v) = Metadata <$> v .: "result_type"+ parseJSON _ = empty++instance ToJSON Geo where+ toJSON Geo{..} = object [+ "type_" .= type_+ , "coordinates" .= coordinates+ ]++ toEncoding Geo{..} = pairs $+ "type_" .= type_+ <> "coordinates" .= coordinates++instance FromJSON Geo where+ parseJSON (Object v) = Geo <$>+ v .: "type_"+ <*> v .: "coordinates"+ parseJSON _ = empty++instance ToJSON Story where+ toJSON Story{..} = object [+ "from_user_id_str" .= from_user_id_str+ , "profile_image_url" .= profile_image_url+ , "created_at" .= created_at+ , "from_user" .= from_user+ , "id_str" .= id_str+ , "metadata" .= metadata+ , "to_user_id" .= to_user_id+ , "text" .= text+ , "id" .= id+ , "from_user_id" .= from_user_id+ , "geo" .= geo+ , "iso_language_code" .= iso_language_code+ , "to_user_id_str" .= to_user_id_str+ , "source" .= source+ ]++ toEncoding Story{..} = pairs $+ "from_user_id_str" .= from_user_id_str+ <> "profile_image_url" .= profile_image_url+ <> "created_at" .= created_at+ <> "from_user" .= from_user+ <> "id_str" .= id_str+ <> "metadata" .= metadata+ <> "to_user_id" .= to_user_id+ <> "text" .= text+ <> "id" .= id+ <> "from_user_id" .= from_user_id+ <> "geo" .= geo+ <> "iso_language_code" .= iso_language_code+ <> "to_user_id_str" .= to_user_id_str+ <> "source" .= source++instance FromJSON Story where+ parseJSON (Object v) = Story <$>+ v .: "from_user_id_str"+ <*> v .: "profile_image_url"+ <*> v .: "created_at"+ <*> v .: "from_user"+ <*> v .: "id_str"+ <*> v .: "metadata"+ <*> v .: "to_user_id"+ <*> v .: "text"+ <*> v .: "id"+ <*> v .: "from_user_id"+ <*> v .: "geo"+ <*> v .: "iso_language_code"+ <*> v .: "to_user_id_str"+ <*> v .: "source"+ parseJSON _ = empty++instance ToJSON Result where+ toJSON Result{..} = object [+ "results" .= results+ , "max_id" .= max_id+ , "since_id" .= since_id+ , "refresh_url" .= refresh_url+ , "next_page" .= next_page+ , "results_per_page" .= results_per_page+ , "page" .= page+ , "completed_in" .= completed_in+ , "since_id_str" .= since_id_str+ , "max_id_str" .= max_id_str+ , "query" .= query+ ]++ toEncoding Result{..} = pairs $+ "results" .= results+ <> "max_id" .= max_id+ <> "since_id" .= since_id+ <> "refresh_url" .= refresh_url+ <> "next_page" .= next_page+ <> "results_per_page" .= results_per_page+ <> "page" .= page+ <> "completed_in" .= completed_in+ <> "since_id_str" .= since_id_str+ <> "max_id_str" .= max_id_str+ <> "query" .= query++instance FromJSON Result where+ parseJSON (Object v) = Result <$>+ v .: "results"+ <*> v .: "max_id"+ <*> v .: "since_id"+ <*> v .: "refresh_url"+ <*> v .: "next_page"+ <*> v .: "results_per_page"+ <*> v .: "page"+ <*> v .: "completed_in"+ <*> v .: "since_id_str"+ <*> v .: "max_id_str"+ <*> v .: "query"+ parseJSON _ = empty
+ examples/Twitter/TH.hs view
@@ -0,0 +1,20 @@+-- Use Template Haskell to generate good instances.++{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Twitter.TH+ (+ Metadata(..)+ , Geo(..)+ , Story(..)+ , Result(..)+ ) where++import Data.Aeson.TH+import Twitter++$(deriveJSON defaultOptions ''Metadata)+$(deriveJSON defaultOptions ''Geo)+$(deriveJSON defaultOptions ''Story)+$(deriveJSON defaultOptions ''Result)
+ examples/aeson-examples.cabal view
@@ -0,0 +1,29 @@+name: aeson-examples+version: 0+build-type: Simple+cabal-version: >=1.8++executable aeson-example-generic+ main-is: Generic.hs+ ghc-options: -Wall+ build-depends:+ aeson >= 0.10,+ base,+ bytestring,+ ghc-prim++executable aeson-example-simplest+ main-is: Simplest.hs+ ghc-options: -Wall+ build-depends:+ aeson,+ base,+ bytestring++executable aeson-example-th+ main-is: TemplateHaskell.hs+ ghc-options: -Wall+ build-depends:+ aeson,+ base,+ bytestring
+ tests/DataFamilies/Encoders.hs view
@@ -0,0 +1,114 @@+{-# Language TemplateHaskell #-}++module DataFamilies.Encoders where++import Data.Aeson.TH+import Data.Aeson.Types+import Options+import DataFamilies.Types++--------------------------------------------------------------------------------+-- Nullary encoders/decoders+--------------------------------------------------------------------------------++thNullaryToJSONString :: Nullary Int -> Value+thNullaryToJSONString = $(mkToJSON defaultOptions 'C1)++thNullaryToEncodingString :: Nullary Int -> Encoding+thNullaryToEncodingString = $(mkToEncoding defaultOptions 'C2)++thNullaryParseJSONString :: Value -> Parser (Nullary Int)+thNullaryParseJSONString = $(mkParseJSON defaultOptions 'C3)+++thNullaryToJSON2ElemArray :: Nullary Int -> Value+thNullaryToJSON2ElemArray = $(mkToJSON opts2ElemArray 'C1)++thNullaryToEncoding2ElemArray :: Nullary Int -> Encoding+thNullaryToEncoding2ElemArray = $(mkToEncoding opts2ElemArray 'C2)++thNullaryParseJSON2ElemArray :: Value -> Parser (Nullary Int)+thNullaryParseJSON2ElemArray = $(mkParseJSON opts2ElemArray 'C3)+++thNullaryToJSONTaggedObject :: Nullary Int -> Value+thNullaryToJSONTaggedObject = $(mkToJSON optsTaggedObject 'C1)++thNullaryToEncodingTaggedObject :: Nullary Int -> Encoding+thNullaryToEncodingTaggedObject = $(mkToEncoding optsTaggedObject 'C2)++thNullaryParseJSONTaggedObject :: Value -> Parser (Nullary Int)+thNullaryParseJSONTaggedObject = $(mkParseJSON optsTaggedObject 'C3)+++thNullaryToJSONObjectWithSingleField :: Nullary Int -> Value+thNullaryToJSONObjectWithSingleField =+ $(mkToJSON optsObjectWithSingleField 'C1)++thNullaryToEncodingObjectWithSingleField :: Nullary Int -> Encoding+thNullaryToEncodingObjectWithSingleField =+ $(mkToEncoding optsObjectWithSingleField 'C2)++thNullaryParseJSONObjectWithSingleField :: Value -> Parser (Nullary Int)+thNullaryParseJSONObjectWithSingleField = $(mkParseJSON optsObjectWithSingleField 'C3)+++--------------------------------------------------------------------------------+-- SomeType encoders/decoders+--------------------------------------------------------------------------------++thSomeTypeToJSON2ElemArray :: SomeType c () Int -> Value+thSomeTypeToJSON2ElemArray = $(mkToJSON opts2ElemArray 'Nullary)++thSomeTypeToEncoding2ElemArray :: SomeType c () Int -> Encoding+thSomeTypeToEncoding2ElemArray = $(mkToEncoding opts2ElemArray 'Unary)++thSomeTypeParseJSON2ElemArray :: Value -> Parser (SomeType c () Int)+thSomeTypeParseJSON2ElemArray = $(mkParseJSON opts2ElemArray 'Product)+++thSomeTypeToJSONTaggedObject :: SomeType c () Int -> Value+thSomeTypeToJSONTaggedObject = $(mkToJSON optsTaggedObject 'Record)++thSomeTypeToEncodingTaggedObject :: SomeType c () Int -> Encoding+thSomeTypeToEncodingTaggedObject = $(mkToEncoding optsTaggedObject 'Nullary)++thSomeTypeParseJSONTaggedObject :: Value -> Parser (SomeType c () Int)+thSomeTypeParseJSONTaggedObject = $(mkParseJSON optsTaggedObject 'Unary)+++thSomeTypeToJSONObjectWithSingleField :: SomeType c () Int -> Value+thSomeTypeToJSONObjectWithSingleField =+ $(mkToJSON optsObjectWithSingleField 'Product)++thSomeTypeToEncodingObjectWithSingleField :: SomeType c () Int -> Encoding+thSomeTypeToEncodingObjectWithSingleField =+ $(mkToEncoding optsObjectWithSingleField 'Record)++thSomeTypeParseJSONObjectWithSingleField :: Value -> Parser (SomeType c () Int)+thSomeTypeParseJSONObjectWithSingleField =+ $(mkParseJSON optsObjectWithSingleField 'Nullary)+++--------------------------------------------------------------------------------+-- Approx encoders/decoders+--------------------------------------------------------------------------------++thApproxToJSONUnwrap :: Approx String -> Value+thApproxToJSONUnwrap = $(mkToJSON optsUnwrapUnaryRecords 'Approx)++thApproxToEncodingUnwrap :: Approx String -> Encoding+thApproxToEncodingUnwrap = $(mkToEncoding optsUnwrapUnaryRecords 'Approx)++thApproxParseJSONUnwrap :: Value -> Parser (Approx String)+thApproxParseJSONUnwrap = $(mkParseJSON optsUnwrapUnaryRecords 'Approx)+++thApproxToJSONDefault :: Approx String -> Value+thApproxToJSONDefault = $(mkToJSON defaultOptions 'Approx)++thApproxToEncodingDefault :: Approx String -> Encoding+thApproxToEncodingDefault = $(mkToEncoding defaultOptions 'Approx)++thApproxParseJSONDefault :: Value -> Parser (Approx String)+thApproxParseJSONDefault = $(mkParseJSON defaultOptions 'Approx)
+ tests/DataFamilies/Types.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, TypeFamilies #-}++module DataFamilies.Types where++import Types (ApproxEq(..))++data family Nullary a+data instance Nullary Int = C1 | C2 | C3 deriving (Eq, Show)+data instance Nullary Char = C4 deriving (Eq, Show)++data family SomeType a b c+data instance SomeType c () a = Nullary+ | Unary Int+ | Product String (Maybe Char) a+ | Record { testOne :: Double+ , testTwo :: Maybe Bool+ , testThree :: Maybe a+ } deriving (Eq, Show)++data family Approx a+newtype instance Approx a = Approx { fromApprox :: a }+ deriving (Show, ApproxEq, Num)++instance (ApproxEq a) => Eq (Approx a) where+ Approx a == Approx b = a =~ b
tests/Encoders.hs view
@@ -1,4 +1,4 @@-{-# Language CPP, TemplateHaskell #-}+{-# Language TemplateHaskell #-} module Encoders where @@ -14,6 +14,9 @@ thNullaryToJSONString :: Nullary -> Value thNullaryToJSONString = $(mkToJSON defaultOptions ''Nullary) +thNullaryToEncodingString :: Nullary -> Encoding+thNullaryToEncodingString = $(mkToEncoding defaultOptions ''Nullary)+ thNullaryParseJSONString :: Value -> Parser Nullary thNullaryParseJSONString = $(mkParseJSON defaultOptions ''Nullary) @@ -21,6 +24,9 @@ thNullaryToJSON2ElemArray :: Nullary -> Value thNullaryToJSON2ElemArray = $(mkToJSON opts2ElemArray ''Nullary) +thNullaryToEncoding2ElemArray :: Nullary -> Encoding+thNullaryToEncoding2ElemArray = $(mkToEncoding opts2ElemArray ''Nullary)+ thNullaryParseJSON2ElemArray :: Value -> Parser Nullary thNullaryParseJSON2ElemArray = $(mkParseJSON opts2ElemArray ''Nullary) @@ -28,17 +34,24 @@ thNullaryToJSONTaggedObject :: Nullary -> Value thNullaryToJSONTaggedObject = $(mkToJSON optsTaggedObject ''Nullary) +thNullaryToEncodingTaggedObject :: Nullary -> Encoding+thNullaryToEncodingTaggedObject = $(mkToEncoding optsTaggedObject ''Nullary)+ thNullaryParseJSONTaggedObject :: Value -> Parser Nullary thNullaryParseJSONTaggedObject = $(mkParseJSON optsTaggedObject ''Nullary) thNullaryToJSONObjectWithSingleField :: Nullary -> Value-thNullaryToJSONObjectWithSingleField = $(mkToJSON optsObjectWithSingleField ''Nullary)+thNullaryToJSONObjectWithSingleField =+ $(mkToJSON optsObjectWithSingleField ''Nullary) +thNullaryToEncodingObjectWithSingleField :: Nullary -> Encoding+thNullaryToEncodingObjectWithSingleField =+ $(mkToEncoding optsObjectWithSingleField ''Nullary)+ thNullaryParseJSONObjectWithSingleField :: Value -> Parser Nullary thNullaryParseJSONObjectWithSingleField = $(mkParseJSON optsObjectWithSingleField ''Nullary) -#ifdef GHC_GENERICS gNullaryToJSONString :: Nullary -> Value gNullaryToJSONString = genericToJSON defaultOptions @@ -65,54 +78,98 @@ gNullaryParseJSONObjectWithSingleField :: Value -> Parser Nullary gNullaryParseJSONObjectWithSingleField = genericParseJSON optsObjectWithSingleField-#endif -------------------------------------------------------------------------------- -- SomeType encoders/decoders -------------------------------------------------------------------------------- -type SomeTypeToJSON = SomeType Int -> Value--thSomeTypeToJSON2ElemArray :: ToJSON a => SomeType a -> Value+thSomeTypeToJSON2ElemArray :: SomeType Int -> Value thSomeTypeToJSON2ElemArray = $(mkToJSON opts2ElemArray ''SomeType) -thSomeTypeParseJSON2ElemArray :: FromJSON a => Value -> Parser (SomeType a)+thSomeTypeToEncoding2ElemArray :: SomeType Int -> Encoding+thSomeTypeToEncoding2ElemArray = $(mkToEncoding opts2ElemArray ''SomeType)++thSomeTypeParseJSON2ElemArray :: Value -> Parser (SomeType Int) thSomeTypeParseJSON2ElemArray = $(mkParseJSON opts2ElemArray ''SomeType) -thSomeTypeToJSONTaggedObject :: ToJSON a => SomeType a -> Value+thSomeTypeToJSONTaggedObject :: SomeType Int -> Value thSomeTypeToJSONTaggedObject = $(mkToJSON optsTaggedObject ''SomeType) -thSomeTypeParseJSONTaggedObject :: FromJSON a => Value -> Parser (SomeType a)+thSomeTypeToEncodingTaggedObject :: SomeType Int -> Encoding+thSomeTypeToEncodingTaggedObject = $(mkToEncoding optsTaggedObject ''SomeType)++thSomeTypeParseJSONTaggedObject :: Value -> Parser (SomeType Int) thSomeTypeParseJSONTaggedObject = $(mkParseJSON optsTaggedObject ''SomeType) -thSomeTypeToJSONObjectWithSingleField :: ToJSON a => SomeType a -> Value-thSomeTypeToJSONObjectWithSingleField = $(mkToJSON optsObjectWithSingleField ''SomeType)+thSomeTypeToJSONObjectWithSingleField :: SomeType Int -> Value+thSomeTypeToJSONObjectWithSingleField =+ $(mkToJSON optsObjectWithSingleField ''SomeType) -thSomeTypeParseJSONObjectWithSingleField :: FromJSON a => Value -> Parser (SomeType a)-thSomeTypeParseJSONObjectWithSingleField = $(mkParseJSON optsObjectWithSingleField ''SomeType)+thSomeTypeToEncodingObjectWithSingleField :: SomeType Int -> Encoding+thSomeTypeToEncodingObjectWithSingleField =+ $(mkToEncoding optsObjectWithSingleField ''SomeType) +thSomeTypeParseJSONObjectWithSingleField :: Value -> Parser (SomeType Int)+thSomeTypeParseJSONObjectWithSingleField =+ $(mkParseJSON optsObjectWithSingleField ''SomeType) -#ifdef GHC_GENERICS-gSomeTypeToJSON2ElemArray :: ToJSON a => SomeType a -> Value++gSomeTypeToJSON2ElemArray :: SomeType Int -> Value gSomeTypeToJSON2ElemArray = genericToJSON opts2ElemArray -gSomeTypeParseJSON2ElemArray :: FromJSON a => Value -> Parser (SomeType a)+gSomeTypeParseJSON2ElemArray :: Value -> Parser (SomeType Int) gSomeTypeParseJSON2ElemArray = genericParseJSON opts2ElemArray -gSomeTypeToJSONTaggedObject :: ToJSON a => SomeType a -> Value+gSomeTypeToJSONTaggedObject :: SomeType Int -> Value gSomeTypeToJSONTaggedObject = genericToJSON optsTaggedObject -gSomeTypeParseJSONTaggedObject :: FromJSON a => Value -> Parser (SomeType a)+gSomeTypeParseJSONTaggedObject :: Value -> Parser (SomeType Int) gSomeTypeParseJSONTaggedObject = genericParseJSON optsTaggedObject -gSomeTypeToJSONObjectWithSingleField :: ToJSON a => SomeType a -> Value+gSomeTypeToJSONObjectWithSingleField :: SomeType Int -> Value gSomeTypeToJSONObjectWithSingleField = genericToJSON optsObjectWithSingleField -gSomeTypeParseJSONObjectWithSingleField :: FromJSON a => Value -> Parser (SomeType a)+gSomeTypeParseJSONObjectWithSingleField :: Value -> Parser (SomeType Int) gSomeTypeParseJSONObjectWithSingleField = genericParseJSON optsObjectWithSingleField-#endif+++--------------------------------------------------------------------------------+-- Approx encoders/decoders+--------------------------------------------------------------------------------++thApproxToJSONUnwrap :: Approx String -> Value+thApproxToJSONUnwrap = $(mkToJSON optsUnwrapUnaryRecords ''Approx)++thApproxToEncodingUnwrap :: Approx String -> Encoding+thApproxToEncodingUnwrap = $(mkToEncoding optsUnwrapUnaryRecords ''Approx)++thApproxParseJSONUnwrap :: Value -> Parser (Approx String)+thApproxParseJSONUnwrap = $(mkParseJSON optsUnwrapUnaryRecords ''Approx)+++thApproxToJSONDefault :: Approx String -> Value+thApproxToJSONDefault = $(mkToJSON defaultOptions ''Approx)++thApproxToEncodingDefault :: Approx String -> Encoding+thApproxToEncodingDefault = $(mkToEncoding defaultOptions ''Approx)++thApproxParseJSONDefault :: Value -> Parser (Approx String)+thApproxParseJSONDefault = $(mkParseJSON defaultOptions ''Approx)++gApproxToJSONUnwrap :: Approx String -> Value+gApproxToJSONUnwrap = genericToJSON optsUnwrapUnaryRecords++gApproxParseJSONUnwrap :: Value -> Parser (Approx String)+gApproxParseJSONUnwrap = genericParseJSON optsUnwrapUnaryRecords+++gApproxToJSONDefault :: Approx String -> Value+gApproxToJSONDefault = genericToJSON defaultOptions++gApproxParseJSONDefault :: Value -> Parser (Approx String)+gApproxParseJSONDefault = genericParseJSON defaultOptions
tests/Instances.hs view
@@ -1,8 +1,5 @@-{-# Language CPP, OverloadedStrings, RecordWildCards, StandaloneDeriving #-}+{-# Language OverloadedStrings, RecordWildCards, StandaloneDeriving #-} {-# OPTIONS_GHC -fno-warn-orphans #-}-#if __GLASGOW_HASKELL__ < 702-{-# OPTIONS_GHC -fno-warn-missing-methods #-}-#endif module Instances where @@ -11,8 +8,10 @@ import Control.Monad import Test.QuickCheck (Arbitrary(..), Gen, choose, oneof, elements) import Data.Time.Clock (DiffTime, UTCTime(..), picosecondsToDiffTime)+import Data.Fixed (Pico) import Data.Time (ZonedTime(..), LocalTime(..), TimeZone(..),- hoursToTimeZone, Day(..), TimeOfDay(..))+ hoursToTimeZone, Day(..), TimeOfDay(..),+ NominalDiffTime) import qualified Data.Text as T import qualified Data.Map as Map import Data.Text (Text)@@ -52,6 +51,9 @@ instance Arbitrary ZonedTime where arbitrary = liftM2 ZonedTime arbitrary arbitrary +instance Arbitrary NominalDiffTime where+ arbitrary = realToFrac <$> (arbitrary :: Gen Pico)+ deriving instance Eq ZonedTime -- Compare equality to within a millisecond, allowing for rounding@@ -145,3 +147,9 @@ , Product <$> arbitrary <*> arbitrary <*> arbitrary , Record <$> arbitrary <*> arbitrary <*> arbitrary ]++instance ApproxEq Char where+ (=~) = (==)++instance (ApproxEq a) => ApproxEq [a] where+ a =~ b = length a == length b && all (uncurry (=~)) (zip a b)
tests/Options.hs view
@@ -15,6 +15,11 @@ , sumEncoding = TwoElemArray } +optsUnwrapUnaryRecords :: Options+optsUnwrapUnaryRecords = optsDefault+ { unwrapUnaryRecords = True+ }+ optsTaggedObject :: Options optsTaggedObject = optsDefault { allNullaryToStringTag = False }
tests/Properties.hs view
@@ -1,144 +1,59 @@-{-# LANGUAGE CPP, OverloadedStrings, RecordWildCards, ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings, RecordWildCards, ScopedTypeVariables #-} -import Control.Monad (forM)+module Properties where+ import Data.Aeson (eitherDecode)-import Data.Aeson.Encode+import Data.Aeson.Encode (encode, encodeToBuilder)+import Data.Aeson.Internal (IResult(..), formatError, ifromJSON, iparse) import Data.Aeson.Parser (value) import Data.Aeson.Types-import Data.Char (toUpper)-import Test.Framework (Test, defaultMain, testGroup)+import Data.ByteString.Builder (toLazyByteString)+import Data.Int (Int8)+import Data.Time (Day, LocalTime, NominalDiffTime, UTCTime, ZonedTime)+import Encoders+import Instances ()+import Test.Framework (Test, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty)-import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (Assertion, assertFailure, assertEqual)-import Test.QuickCheck (Arbitrary(..))-import qualified Data.Vector as V+import Test.QuickCheck (Arbitrary(..), Property, (===))+import Types import qualified Data.Attoparsec.Lazy as L import qualified Data.ByteString.Lazy.Char8 as L-import qualified Data.Text as T-import qualified Data.Text.Lazy.Builder as TLB-import qualified Data.Text.Lazy.Encoding as TLE import qualified Data.HashMap.Strict as H-import Data.Time-import Instances ()-import Types-import Encoders-import Properties.Deprecated (deprecatedTests)-import System.IO-import System.IO.Unsafe (unsafePerformIO)--#ifdef GHC_GENERICS-import Data.Int import qualified Data.Map as Map-#endif--#if !MIN_VERSION_time(1,5,0)-import System.Locale (defaultTimeLocale, dateTimeFmt)-#endif---roundTripCamel :: String -> Assertion-roundTripCamel name = assertEqual "" name (camelFrom '_' $ camelTo '_' name)--- where- camelFrom c s = let (p:ps) = split c s- in concat $ p : map capitalize ps- split c s = map L.unpack $ L.split c $ L.pack s- capitalize t = toUpper (head t) : tail t+import qualified Data.Text as T+import qualified Data.Vector as V -encodeDouble :: Double -> Double -> Bool+encodeDouble :: Double -> Double -> Property encodeDouble num denom- | isInfinite d || isNaN d = encode d == "null"- | otherwise = (read . L.unpack . encode) d == d+ | isInfinite d || isNaN d = encode d === "null"+ | otherwise = (read . L.unpack . encode) d === d where d = num / denom -encodeInteger :: Integer -> Bool-encodeInteger i = encode i == L.pack (show i)+encodeInteger :: Integer -> Property+encodeInteger i = encode i === L.pack (show i) -toParseJSON :: (Arbitrary a, Eq a) => (Value -> Parser a) -> (a -> Value) -> a -> Bool+toParseJSON :: (Arbitrary a, Eq a, Show a) =>+ (Value -> Parser a) -> (a -> Value) -> a -> Property toParseJSON parsejson tojson x =- case parse parsejson . tojson $ x of- Error _ -> False- Success x' -> x == x'+ case iparse parsejson . tojson $ x of+ IError path msg -> failure "parse" (formatError path msg) x+ ISuccess x' -> x === x' -roundTrip :: (FromJSON a, ToJSON a) => (a -> a -> Bool) -> a -> a -> Bool+roundTrip :: (FromJSON a, ToJSON a, Show a) =>+ (a -> a -> Property) -> a -> a -> Property roundTrip eq _ i =- case fmap fromJSON . L.parse value . encode . toJSON $ i of- L.Done _ (Success v) -> v `eq` i- _ -> False--roundTripEq :: (Eq a, FromJSON a, ToJSON a) => a -> a -> Bool-roundTripEq x y = roundTrip (==) x y--toFromJSON :: (Arbitrary a, Eq a, FromJSON a, ToJSON a) => a -> Bool-toFromJSON x = case fromJSON . toJSON $ x of- Error _ -> False- Success x' -> x == x'--zonedTimeToJSON :: ZonedTime -> Bool-zonedTimeToJSON t = and $- toFromJSON' "%FT%T%QZ" t (clearTimeZone t) : -- (javascript new Date().toISOString())- toFromJSON' "%F %T%Q%z" t t : -- (postgres)- toFromJSON' "%F %T%Q %Z" t t : -- (time's Show format)- toFromJSON' "%FT%T%Q%z" t t :- toFromJSON' "%Y-%mT%T%Q" t (clearTimeZone . clearDay $ t) :- toFromJSON' "%Y-%mT%R" t (clearTimeZone . clearDay . clearSeconds $ t) :- toFromJSON' "%Y-%mT%T" t (clearTimeZone . clearDay $ t) :- toFromJSON' "%Y-%mT%T%QZ" t (clearTimeZone . clearDay $ t) :- toFromJSON' "%Y-%mT%T%Q%z" t (clearDay t) :- toFromJSON' "%YT%T%Q" t (clearTimeZone . clearMonth . clearDay $ t) :- toFromJSON' "%YT%R" t (clearTimeZone . clearMonth . clearDay . clearSeconds $ t) :- toFromJSON' "%YT%T" t (clearTimeZone . clearMonth . clearDay $ t) :- toFromJSON' "%YT%T%QZ" t (clearTimeZone . clearMonth . clearDay $ t) :- toFromJSON' "%YT%T%Q%z" t (clearMonth . clearDay $ t) :- toFromJSON' "%FT%T%Q" t (clearTimeZone t) :- toFromJSON' "%FT%R" t (clearTimeZone . clearSeconds $ t) :- toFromJSON' "%FT%T" t (clearTimeZone t) :- toFromJSON' (dateTimeFmt defaultTimeLocale) t t :- []- where- toJSON' :: String -> ZonedTime -> Value- toJSON' format = toJSON . formatTime defaultTimeLocale format-- toFromJSON' :: String -> ZonedTime -> ZonedTime -> Bool- toFromJSON' format t_ t_' = case fromJSON . toJSON' format $ t_ of- Error msg -> error' msg- Success t_'' -> if t_'' == t_' then True else error' (show t_'')- where- error' :: String -> Bool- error' msg = unsafePerformIO (hPutStrLn stderr . ("zonedTimeToJSON: " ++) $ show- (format, t_, toJSON' format t_, t_', msg))- `seq` False--clearTimeZone :: ZonedTime -> ZonedTime-clearTimeZone t = t { zonedTimeZone = TimeZone 0 False "" }--clearMonth :: ZonedTime -> ZonedTime-clearMonth = f- where- f zt = zt { zonedTimeToLocalTime = g $ zonedTimeToLocalTime zt }- g lt = lt { localDay = h $ localDay lt }-- h :: Day -> Day- h = maybe (error "clearMonth") id . parseTime defaultTimeLocale "%Y-%m-%d" . formatTime defaultTimeLocale "%Y-01-%d"--clearDay :: ZonedTime -> ZonedTime-clearDay = f- where- f zt = zt { zonedTimeToLocalTime = g $ zonedTimeToLocalTime zt }- g lt = lt { localDay = h $ localDay lt }-- h :: Day -> Day- h = maybe (error "clearDay") id . parseTime defaultTimeLocale "%Y-%m-%d" . formatTime defaultTimeLocale "%Y-%m-01"+ case fmap ifromJSON . L.parse value . encode . toJSON $ i of+ L.Done _ (ISuccess v) -> v `eq` i+ L.Done _ (IError path err) -> failure "fromJSON" (formatError path err) i+ L.Fail _ _ err -> failure "parse" err i -clearSeconds :: ZonedTime -> ZonedTime-clearSeconds = f- where- f zt = zt { zonedTimeToLocalTime = g $ zonedTimeToLocalTime zt }- g lt = lt { localTimeOfDay = h $ localTimeOfDay lt }+roundTripEq :: (Eq a, FromJSON a, ToJSON a, Show a) => a -> a -> Property+roundTripEq x y = roundTrip (===) x y - h :: TimeOfDay -> TimeOfDay- h = maybe (error "clearSeconds") id . parseTime defaultTimeLocale "%H:%M:%S" . formatTime defaultTimeLocale "%H:%M:00"+toFromJSON :: (Arbitrary a, Eq a, FromJSON a, ToJSON a, Show a) => a -> Property+toFromJSON x = case ifromJSON (toJSON x) of+ IError path err -> failure "fromJSON" (formatError path err) x+ ISuccess x' -> x === x' modifyFailureProp :: String -> String -> Bool modifyFailureProp orig added =@@ -148,15 +63,20 @@ result :: Result () result = parse parser () -main :: IO ()-main = do- comparisonTest <- encoderComparisonTests- defaultMain (comparisonTest : tests)+-- | Perform a bit-for-bit comparison of two encoding methods.+sameAs :: (a -> Value) -> (a -> Encoding) -> a -> Property+sameAs toVal toEnc v =+ toLazyByteString (encodeToBuilder (toVal v)) ===+ toLazyByteString (fromEncoding (toEnc v)) -#ifdef GHC_GENERICS+-- | Behaves like 'sameAs', but compares decoded values to account for+-- HashMap-driven variation in JSON object key ordering.+sameAsV :: (a -> Value) -> (a -> Encoding) -> a -> Property+sameAsV toVal toEnc v =+ eitherDecode (toLazyByteString (fromEncoding (toEnc v))) === Right (toVal v)+ type P6 = Product6 Int Bool String (Approx Double) (Int, Approx Double) () type S4 = Sum4 Int8 ZonedTime T.Text (Map.Map String Int)-#endif -------------------------------------------------------------------------------- -- Value properties@@ -185,18 +105,13 @@ -------------------------------------------------------------------------------- -tests :: [Test]-tests = [+tests :: Test+tests = testGroup "properties" [ testGroup "encode" [ testProperty "encodeDouble" encodeDouble , testProperty "encodeInteger" encodeInteger- ],- testGroup "camelCase" [- testCase "camelTo" $ roundTripCamel "aName"- , testCase "camelTo" $ roundTripCamel "another"- , testCase "camelTo" $ roundTripCamel "someOtherName"- ],- testGroup "roundTrip" [+ ]+ , testGroup "roundTrip" [ testProperty "Bool" $ roundTripEq True , testProperty "Double" $ roundTripEq (1 :: Approx Double) , testProperty "Int" $ roundTripEq (1 :: Int)@@ -204,127 +119,84 @@ , testProperty "String" $ roundTripEq ("" :: String) , testProperty "Text" $ roundTripEq T.empty , testProperty "Foo" $ roundTripEq (undefined :: Foo)+ , testProperty "Day" $ roundTripEq (undefined :: Day) , testProperty "DotNetTime" $ roundTripEq (undefined :: DotNetTime)+ , testProperty "LocalTime" $ roundTripEq (undefined :: LocalTime) , testProperty "UTCTime" $ roundTripEq (undefined :: UTCTime) , testProperty "ZonedTime" $ roundTripEq (undefined :: ZonedTime)-#ifdef GHC_GENERICS+ , testProperty "NominalDiffTime" $ roundTripEq (undefined :: NominalDiffTime) , testGroup "ghcGenerics" [ testProperty "OneConstructor" $ roundTripEq OneConstructor , testProperty "Product2" $ roundTripEq (undefined :: Product2 Int Bool) , testProperty "Product6" $ roundTripEq (undefined :: P6) , testProperty "Sum4" $ roundTripEq (undefined :: S4) ]-#endif- ],- testGroup "toFromJSON" [- testProperty "Integer" (toFromJSON :: Integer -> Bool)- , testProperty "Double" (toFromJSON :: Double -> Bool)- , testProperty "Maybe Integer" (toFromJSON :: Maybe Integer -> Bool)- , testProperty "Either Integer Double" (toFromJSON :: Either Integer Double -> Bool)- , testProperty "Either Integer Integer" (toFromJSON :: Either Integer Integer -> Bool)- , testProperty "ZonedTime" $ zonedTimeToJSON- ],- testGroup "deprecated" deprecatedTests,- testGroup "failure messages" [+ ]+ , testGroup "toFromJSON" [+ testProperty "Integer" (toFromJSON :: Integer -> Property)+ , testProperty "Double" (toFromJSON :: Double -> Property)+ , testProperty "Maybe Integer" (toFromJSON :: Maybe Integer -> Property)+ , testProperty "Either Integer Double" (toFromJSON :: Either Integer Double -> Property)+ , testProperty "Either Integer Integer" (toFromJSON :: Either Integer Integer -> Property)+ ]+ , testGroup "failure messages" [ testProperty "modify failure" modifyFailureProp- ],- testGroup "template-haskell" [- testGroup "Nullary" [- testProperty "string" (isString . thNullaryToJSONString)- , testProperty "2ElemArray" (is2ElemArray . thNullaryToJSON2ElemArray)- , testProperty "TaggedObject" (isTaggedObjectValue . thNullaryToJSONTaggedObject)- , testProperty "ObjectWithSingleField" (isObjectWithSingleField . thNullaryToJSONObjectWithSingleField)+ ]+ , testGroup "template-haskell" [+ testGroup "toJSON" [+ testGroup "Nullary" [+ testProperty "string" (isString . thNullaryToJSONString)+ , testProperty "2ElemArray" (is2ElemArray . thNullaryToJSON2ElemArray)+ , testProperty "TaggedObject" (isTaggedObjectValue . thNullaryToJSONTaggedObject)+ , testProperty "ObjectWithSingleField" (isObjectWithSingleField . thNullaryToJSONObjectWithSingleField) - , testGroup "roundTrip" [- testProperty "string" (toParseJSON thNullaryParseJSONString thNullaryToJSONString)- , testProperty "2ElemArray" (toParseJSON thNullaryParseJSON2ElemArray thNullaryToJSON2ElemArray)- , testProperty "TaggedObject" (toParseJSON thNullaryParseJSONTaggedObject thNullaryToJSONTaggedObject)+ , testGroup "roundTrip" [+ testProperty "string" (toParseJSON thNullaryParseJSONString thNullaryToJSONString)+ , testProperty "2ElemArray" (toParseJSON thNullaryParseJSON2ElemArray thNullaryToJSON2ElemArray)+ , testProperty "TaggedObject" (toParseJSON thNullaryParseJSONTaggedObject thNullaryToJSONTaggedObject) , testProperty "ObjectWithSingleField" (toParseJSON thNullaryParseJSONObjectWithSingleField thNullaryToJSONObjectWithSingleField)- ]+ ] ]- , testGroup "SomeType" [- testProperty "2ElemArray" (is2ElemArray . (thSomeTypeToJSON2ElemArray :: SomeTypeToJSON))- , testProperty "TaggedObject" (isTaggedObject . (thSomeTypeToJSONTaggedObject :: SomeTypeToJSON))- , testProperty "ObjectWithSingleField" (isObjectWithSingleField . (thSomeTypeToJSONObjectWithSingleField :: SomeTypeToJSON))-+ , testGroup "SomeType" [+ testProperty "2ElemArray" (is2ElemArray . thSomeTypeToJSON2ElemArray)+ , testProperty "TaggedObject" (isTaggedObject . thSomeTypeToJSONTaggedObject)+ , testProperty "ObjectWithSingleField" (isObjectWithSingleField . thSomeTypeToJSONObjectWithSingleField) , testGroup "roundTrip" [- testProperty "2ElemArray" (toParseJSON thSomeTypeParseJSON2ElemArray (thSomeTypeToJSON2ElemArray :: SomeTypeToJSON))- , testProperty "TaggedObject" (toParseJSON thSomeTypeParseJSONTaggedObject (thSomeTypeToJSONTaggedObject :: SomeTypeToJSON))- , testProperty "ObjectWithSingleField" (toParseJSON thSomeTypeParseJSONObjectWithSingleField (thSomeTypeToJSONObjectWithSingleField :: SomeTypeToJSON))+ testProperty "2ElemArray" (toParseJSON thSomeTypeParseJSON2ElemArray thSomeTypeToJSON2ElemArray)+ , testProperty "TaggedObject" (toParseJSON thSomeTypeParseJSONTaggedObject thSomeTypeToJSONTaggedObject)+ , testProperty "ObjectWithSingleField" (toParseJSON thSomeTypeParseJSONObjectWithSingleField thSomeTypeToJSONObjectWithSingleField) ]- ]- ]-#ifdef GHC_GENERICS- , testGroup "GHC-generics" [- testGroup "Nullary" [- testProperty "string" (isString . gNullaryToJSONString)- , testProperty "2ElemArray" (is2ElemArray . gNullaryToJSON2ElemArray)- , testProperty "TaggedObject" (isTaggedObjectValue . gNullaryToJSONTaggedObject)- , testProperty "ObjectWithSingleField" (isObjectWithSingleField . gNullaryToJSONObjectWithSingleField)- , testGroup "eq" [- testProperty "string" (\n -> gNullaryToJSONString n == thNullaryToJSONString n)- , testProperty "2ElemArray" (\n -> gNullaryToJSON2ElemArray n == thNullaryToJSON2ElemArray n)- , testProperty "TaggedObject" (\n -> gNullaryToJSONTaggedObject n == thNullaryToJSONTaggedObject n)- , testProperty "ObjectWithSingleField" (\n -> gNullaryToJSONObjectWithSingleField n == thNullaryToJSONObjectWithSingleField n)- ]+ , testGroup "Approx" [+ testProperty "string" (isString . thApproxToJSONUnwrap)+ , testProperty "ObjectWithSingleField" (isObjectWithSingleField . thApproxToJSONDefault) , testGroup "roundTrip" [- testProperty "string" (toParseJSON gNullaryParseJSONString gNullaryToJSONString)- , testProperty "2ElemArray" (toParseJSON gNullaryParseJSON2ElemArray gNullaryToJSON2ElemArray)- , testProperty "TaggedObject" (toParseJSON gNullaryParseJSONTaggedObject gNullaryToJSONTaggedObject)- , testProperty "ObjectWithSingleField" (toParseJSON gNullaryParseJSONObjectWithSingleField gNullaryToJSONObjectWithSingleField)+ testProperty "string" (toParseJSON thApproxParseJSONUnwrap thApproxToJSONUnwrap)+ , testProperty "ObjectWithSingleField" (toParseJSON thApproxParseJSONDefault thApproxToJSONDefault) ] ]- , testGroup "SomeType" [- testProperty "2ElemArray" (is2ElemArray . (gSomeTypeToJSON2ElemArray :: SomeTypeToJSON))- , testProperty "TaggedObject" (isTaggedObject . (gSomeTypeToJSONTaggedObject :: SomeTypeToJSON))- , testProperty "ObjectWithSingleField" (isObjectWithSingleField . (gSomeTypeToJSONObjectWithSingleField :: SomeTypeToJSON))-- , testGroup "eq" [- testProperty "2ElemArray" (\n -> (gSomeTypeToJSON2ElemArray :: SomeTypeToJSON) n == thSomeTypeToJSON2ElemArray n)- , testProperty "TaggedObject" (\n -> (gSomeTypeToJSONTaggedObject :: SomeTypeToJSON) n == thSomeTypeToJSONTaggedObject n)- , testProperty "ObjectWithSingleField" (\n -> (gSomeTypeToJSONObjectWithSingleField :: SomeTypeToJSON) n == thSomeTypeToJSONObjectWithSingleField n)- ]- , testGroup "roundTrip" [- testProperty "2ElemArray" (toParseJSON gSomeTypeParseJSON2ElemArray (gSomeTypeToJSON2ElemArray :: SomeTypeToJSON))- , testProperty "TaggedObject" (toParseJSON gSomeTypeParseJSONTaggedObject (gSomeTypeToJSONTaggedObject :: SomeTypeToJSON))- , testProperty "ObjectWithSingleField" (toParseJSON gSomeTypeParseJSONObjectWithSingleField (gSomeTypeToJSONObjectWithSingleField :: SomeTypeToJSON))- ]+ ] ]+ , testGroup "toEncoding" [+ testProperty "NullaryString" $+ thNullaryToJSONString `sameAs` thNullaryToEncodingString+ , testProperty "Nullary2ElemArray" $+ thNullaryToJSON2ElemArray `sameAs` thNullaryToEncoding2ElemArray+ , testProperty "NullaryTaggedObject" $+ thNullaryToJSONTaggedObject `sameAs` thNullaryToEncodingTaggedObject+ , testProperty "NullaryObjectWithSingleField" $+ thNullaryToJSONObjectWithSingleField `sameAs`+ thNullaryToEncodingObjectWithSingleField+ , testProperty "ApproxUnwrap" $+ thApproxToJSONUnwrap `sameAs` thApproxToEncodingUnwrap+ , testProperty "ApproxDefault" $+ thApproxToJSONDefault `sameAs` thApproxToEncodingDefault+ , testProperty "SomeType2ElemArray" $+ thSomeTypeToJSON2ElemArray `sameAsV` thSomeTypeToEncoding2ElemArray+ , testProperty "SomeTypeTaggedObject" $+ thSomeTypeToJSONTaggedObject `sameAsV` thSomeTypeToEncodingTaggedObject+ , testProperty "SomeTypeObjectWithSingleField" $+ thSomeTypeToJSONObjectWithSingleField `sameAsV`+ thSomeTypeToEncodingObjectWithSingleField+ ] ]-#endif ]------------------------------------------------------------------------------------ Comparison between bytestring and text encoders---------------------------------------------------------------------------------encoderComparisonTests :: IO Test-encoderComparisonTests = do- encoderTests <- forM testFiles $ \file0 -> do- let file = "benchmarks/json-data/" ++ file0- return $ testCase file $ do- inp <- L.readFile file- case eitherDecode inp of- Left err -> assertFailure $ "Decoding failure: " ++ err- Right val -> assertEqual "" (encode val) (encodeViaText val)- return $ testGroup "Compare bytestring and text encoders" encoderTests- where- encodeViaText :: Value -> L.ByteString- encodeViaText =- TLE.encodeUtf8 . TLB.toLazyText . encodeToTextBuilder . toJSON-- testFiles =- [ "example.json"- , "integers.json"- , "jp100.json"- , "numbers.json"- , "twitter10.json"- , "twitter20.json"- , "geometry.json"- , "jp10.json"- , "jp50.json"- , "twitter1.json"- , "twitter100.json"- , "twitter50.json"- ]
− tests/Properties/Deprecated.hs
@@ -1,57 +0,0 @@--- This module is only for testing deprecated features, so we can--- silence compiler warnings selectively.--{-# LANGUAGE OverloadedStrings, RecordWildCards, ScopedTypeVariables #-}-{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}--module Properties.Deprecated (deprecatedTests) where--import Data.Aeson.Types-import Data.Data (Data)-import Test.Framework (Test, testGroup)-import Test.Framework.Providers.QuickCheck2 (testProperty)-import Test.QuickCheck (Arbitrary(..))-import qualified Data.Aeson.Generic as G-import qualified Data.Map as Map-import Types (Foo(..), UFoo(..))-import Instances ()---genericTo :: (Data a, ToJSON a) => a -> a -> Bool-genericTo _ v = G.toJSON v == toJSON v--genericFrom :: (Eq a, Data a, ToJSON a) => a -> a -> Bool-genericFrom _ v = G.fromJSON (toJSON v) == Success v--genericToFromJSON :: (Arbitrary a, Eq a, Data a) => a -> Bool-genericToFromJSON x = case G.fromJSON . G.toJSON $ x of- Error _ -> False- Success x' -> x == x'--regress_gh72 :: [(String, Maybe String)] -> Bool-regress_gh72 ys = G.decode (G.encode m) == Just m- where m = Map.fromList ys--deprecatedTests :: [Test]-deprecatedTests = [- testGroup "regression" [- testProperty "gh-72" regress_gh72- ],- testGroup "genericFrom" [- testProperty "Bool" $ genericFrom True- , testProperty "Double" $ genericFrom (1::Double)- , testProperty "Int" $ genericFrom (1::Int)- , testProperty "Foo" $ genericFrom (undefined::Foo)- , testProperty "Maybe" $ genericFrom (Just 1 :: Maybe Int)- ],- testGroup "genericTo" [- testProperty "Bool" $ genericTo True- , testProperty "Double" $ genericTo (1::Double)- , testProperty "Int" $ genericTo (1::Int)- , testProperty "Foo" $ genericTo (undefined::Foo)- , testProperty "Maybe" $ genericTo (Just 1 :: Maybe Int)- ],- testGroup "genericToFromJSON" [- testProperty "_UFoo" (genericToFromJSON :: UFoo -> Bool)- ]- ]
+ tests/Tests.hs view
@@ -0,0 +1,11 @@+module Main (main) where++import Test.Framework (defaultMain)+import qualified DataFamilies.Properties as DF+import qualified Properties+import qualified UnitTests++main :: IO ()+main = do+ ioTests <- UnitTests.ioTests+ defaultMain (DF.tests : Properties.tests : UnitTests.tests : ioTests)
tests/Types.hs view
@@ -1,16 +1,13 @@-{-# LANGUAGE CPP, DeriveDataTypeable, GeneralizedNewtypeDeriving #-}-#ifdef GHC_GENERICS+{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving #-} {-# LANGUAGE DeriveGeneric, StandaloneDeriving #-}-#endif module Types where import qualified Data.Map as Map import Data.Data import Data.Text-#ifdef GHC_GENERICS import GHC.Generics-#endif+import Test.QuickCheck (Property, counterexample) data Foo = Foo { fooInt :: Int@@ -57,7 +54,6 @@ , testThree :: Maybe a } deriving (Eq, Show) -#ifdef GHC_GENERICS deriving instance Generic Foo deriving instance Generic UFoo deriving instance Generic OneConstructor@@ -67,4 +63,7 @@ deriving instance Generic (Approx a) deriving instance Generic Nullary deriving instance Generic (SomeType a)-#endif++failure :: Show a => String -> String -> a -> Property+failure func msg v = counterexample+ (func ++ " failed: " ++ msg ++ ", " ++ show v) False
+ tests/UnitTests.hs view
@@ -0,0 +1,186 @@+{-# LANGUAGE CPP, DeriveGeneric, OverloadedStrings, ScopedTypeVariables #-}++module UnitTests (ioTests, tests) where++import Control.Monad (forM)+import Data.Aeson (decode, eitherDecode, encode, genericToJSON, genericToEncoding)+import Data.Aeson.Encode (encodeToTextBuilder)+import Data.Aeson.Types (ToJSON(..), Value, camelTo, camelTo2, defaultOptions)+import Data.Char (toUpper)+import Data.Time (UTCTime)+import Data.Time.Format (parseTime)+import GHC.Generics (Generic)+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit (Assertion, assertFailure, assertEqual)+import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.Text.Lazy.Builder as TLB+import qualified Data.Text.Lazy.Encoding as TLE+import qualified Data.Text.Lazy as LT+import qualified Data.Text.Lazy.Encoding as LT++#if MIN_VERSION_time(1,5,0)+import Data.Time.Format (defaultTimeLocale)+#else+import System.Locale (defaultTimeLocale)+#endif++tests :: Test+tests = testGroup "unit" [+ testGroup "camelCase" [+ testCase "camelTo" $ roundTripCamel "aName"+ , testCase "camelTo" $ roundTripCamel "another"+ , testCase "camelTo" $ roundTripCamel "someOtherName"+ , testCase "camelTo" $+ assertEqual "" "camel_apicase" (camelTo '_' "CamelAPICase")+ , testCase "camelTo2" $ roundTripCamel2 "aName"+ , testCase "camelTo2" $ roundTripCamel2 "another"+ , testCase "camelTo2" $ roundTripCamel2 "someOtherName"+ , testCase "camelTo2" $+ assertEqual "" "camel_api_case" (camelTo2 '_' "CamelAPICase")+ ]+ , testGroup "encoding" [+ testCase "goodProducer" $ goodProducer+ ]+ , testGroup "utctime" [+ testCase "good" $ utcTimeGood+ , testCase "bad" $ utcTimeBad+ ]+ ]++roundTripCamel :: String -> Assertion+roundTripCamel name = assertEqual "" name (camelFrom '_' $ camelTo '_' name)++roundTripCamel2 :: String -> Assertion+roundTripCamel2 name = assertEqual "" name (camelFrom '_' $ camelTo2 '_' name)++camelFrom :: Char -> String -> String+camelFrom c s = let (p:ps) = split c s+ in concat $ p : map capitalize ps+ where+ split c s = map L.unpack $ L.split c $ L.pack s+ capitalize t = toUpper (head t) : tail t++data Wibble = Wibble {+ wibbleString :: String+ , wibbleInt :: Int+ } deriving (Generic, Show)++instance ToJSON Wibble where+ toJSON = genericToJSON defaultOptions+ toEncoding = genericToEncoding defaultOptions++-- Test that if we put a bomb in a data structure, but only demand+-- part of it via lazy encoding, we do not unexpectedly fail.+goodProducer :: Assertion+goodProducer = assertEqual "partial encoding should not explode on undefined"+ '{' (L.head (encode wibble))+ where+ wibble = Wibble {+ wibbleString = replicate 4030 'a'+ , wibbleInt = undefined+ }++-- Test decoding various UTC time formats+--+-- Note: the incomplete pattern matches for UTCTimes are completely+-- intentional. The test expects these parses to succeed. If the+-- pattern matches fails, there's a bug in either the test or in aeson+-- and needs to be investigated.+utcTimeGood :: Assertion+utcTimeGood = do+ let ts1 = "2015-01-01T12:13:00.00Z" :: LT.Text+ let ts2 = "2015-01-01T12:13:00Z" :: LT.Text+ -- 'T' between date and time is not required, can be space+ let ts3 = "2015-01-03 12:13:00.00Z" :: LT.Text+ let ts4 = "2015-01-03 12:13:00.125Z" :: LT.Text+ let (Just (t1 :: UTCTime)) = parseWithAeson ts1+ let (Just (t2 :: UTCTime)) = parseWithAeson ts2+ let (Just (t3 :: UTCTime)) = parseWithAeson ts3+ let (Just (t4 :: UTCTime)) = parseWithAeson ts4+ assertEqual "utctime" (parseWithRead "%FT%T%QZ" ts1) t1+ assertEqual "utctime" (parseWithRead "%FT%T%QZ" ts2) t2+ assertEqual "utctime" (parseWithRead "%F %T%QZ" ts3) t3+ assertEqual "utctime" (parseWithRead "%F %T%QZ" ts4) t4+ -- Time zones. Both +HHMM and +HH:MM are allowed for timezone+ -- offset, and MM may be omitted.+ let ts5 = "2015-01-01T12:30:00.00+00" :: LT.Text+ let ts6 = "2015-01-01T12:30:00.00+01:15" :: LT.Text+ let ts7 = "2015-01-01T12:30:00.00-02" :: LT.Text+ let ts8 = "2015-01-01T22:00:00.00-03" :: LT.Text+ let ts9 = "2015-01-01T22:00:00.00-04:30" :: LT.Text+ let (Just (t5 :: UTCTime)) = parseWithAeson ts5+ let (Just (t6 :: UTCTime)) = parseWithAeson ts6+ let (Just (t7 :: UTCTime)) = parseWithAeson ts7+ let (Just (t8 :: UTCTime)) = parseWithAeson ts8+ let (Just (t9 :: UTCTime)) = parseWithAeson ts9+ assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-01T12:30:00.00Z") t5+ assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-01T11:15:00.00Z") t6+ assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-01T14:30:00Z") t7+ -- ts8 wraps around to the next day in UTC+ assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-02T01:00:00Z") t8+ assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-02T02:30:00Z") t9+ where+ parseWithRead :: String -> LT.Text -> UTCTime+ parseWithRead f s =+ case parseTime defaultTimeLocale f . LT.unpack $ s of+ Nothing -> error "parseTime input malformed"+ Just t -> t+ parseWithAeson :: LT.Text -> Maybe UTCTime+ parseWithAeson s = decode . LT.encodeUtf8 $ (LT.concat ["\"", s, "\""])++-- Test that a few non-timezone qualified timestamp formats get+-- rejected if decoding to UTCTime.+utcTimeBad :: Assertion+utcTimeBad = do+ verifyFailParse "2000-01-01T12:13:00" -- missing Zulu time not allowed (some TZ required)+ verifyFailParse "2000-01-01 12:13:00" -- missing Zulu time not allowed (some TZ required)+ verifyFailParse "2000-01-01" -- date only not OK+ verifyFailParse "2000-01-01Z" -- date only not OK+ verifyFailParse "2015-01-01T12:30:00.00+00Z" -- no Zulu if offset given+ verifyFailParse "2015-01-01T12:30:00.00+00:00Z" -- no Zulu if offset given+ verifyFailParse "2015-01-03 12:13:00.Z" -- decimal at the end but no digits+ where+ verifyFailParse (s :: LT.Text) =+ let (dec :: Maybe UTCTime) = decode . LT.encodeUtf8 $ (LT.concat ["\"", s, "\""]) in+ assertEqual "verify failure" Nothing dec+++------------------------------------------------------------------------------+-- Comparison between bytestring and text encoders+------------------------------------------------------------------------------++ioTests :: IO [Test]+ioTests = do+ enc <- encoderComparisonTests+ return [enc]++encoderComparisonTests :: IO Test+encoderComparisonTests = do+ encoderTests <- forM testFiles $ \file0 -> do+ let file = "benchmarks/json-data/" ++ file0+ return $ testCase file $ do+ inp <- L.readFile file+ case eitherDecode inp of+ Left err -> assertFailure $ "Decoding failure: " ++ err+ Right val -> assertEqual "" (encode val) (encodeViaText val)+ return $ testGroup "encoders" encoderTests+ where+ encodeViaText :: Value -> L.ByteString+ encodeViaText =+ TLE.encodeUtf8 . TLB.toLazyText . encodeToTextBuilder . toJSON++ testFiles =+ [ "example.json"+ , "integers.json"+ , "jp100.json"+ , "numbers.json"+ , "twitter10.json"+ , "twitter20.json"+ , "geometry.json"+ , "jp10.json"+ , "jp50.json"+ , "twitter1.json"+ , "twitter100.json"+ , "twitter50.json"+ ]