highjson 0.2.0.2 → 0.3.0.0
raw patch · 13 files changed
+555/−841 lines, 13 filesdep +lensdep −attoparsecdep −buffer-builderdep −containersdep ~aesondep ~basedep ~bytestringPVP ok
version bump matches the API change (PVP)
Dependencies added: lens
Dependencies removed: attoparsec, buffer-builder, containers, hashable, scientific, unordered-containers, vector
Dependency ranges changed: aeson, base, bytestring
API changes (from Hackage documentation)
- Data.Json: (.->) :: ConstrTagger r => Text -> Parser (ResultType r) -> r
- Data.Json: (.<-) :: ToJson a => Text -> a -> KeyedSerialiser k
- Data.Json: (.=) :: (ToJson t, JsonReadable t, Typeable t) => TypedKey t -> (k -> t) -> FieldKey k t
- Data.Json: (.=?) :: (ToJson t, JsonReadable t, Typeable t) => TypedKey (Maybe t) -> (k -> Maybe t) -> FieldKey k (Maybe t)
- Data.Json: (:+:) :: !(FieldKey k t) -> !(FieldSpec k ts) -> FieldSpec k (t : ts)
- Data.Json: (<||>) :: KeyedConstr k -> ParseSpec k -> ParseSpec k
- Data.Json: EmptySpec :: FieldSpec k []
- Data.Json: JsonSpec :: !(HVectElim ts k) -> !(FieldSpec k ts) -> JsonSpec k
- Data.Json: JsonSumSpec :: !(ParseSpec k) -> !(k -> KeyedSerialiser k) -> JsonSumSpec k
- Data.Json: class JsonReadable t
- Data.Json: class ToJson a
- Data.Json: data FieldKey k t
- Data.Json: data FieldSpec k (ts :: [*])
- Data.Json: data JsonSpec k (ts :: [*])
- Data.Json: data JsonSumSpec k
- Data.Json: data TypedKey t
- Data.Json: j_constr :: JsonSpec k -> !(HVectElim ts k)
- Data.Json: j_fields :: JsonSpec k -> !(FieldSpec k ts)
- Data.Json: js_parser :: JsonSumSpec k -> !(ParseSpec k)
- Data.Json: js_serialiser :: JsonSumSpec k -> !(k -> KeyedSerialiser k)
- Data.Json: makeParser :: JsonSpec k ts -> Parser k
- Data.Json: makeSerialiser :: JsonSpec k ts -> k -> Value
- Data.Json: makeSumParser :: JsonSumSpec k -> Parser k
- Data.Json: makeSumSerialiser :: JsonSumSpec k -> k -> Value
- Data.Json: optKey :: Typeable t => Text -> TypedKey (Maybe t)
- Data.Json: parseJsonBs :: JsonReadable t => ByteString -> Either String t
- Data.Json: parseJsonBsl :: JsonReadable t => ByteString -> Either String t
- Data.Json: parseJsonT :: JsonReadable t => Text -> Either String t
- Data.Json: readJson :: JsonReadable t => Parser t
- Data.Json: reqKey :: Typeable t => Text -> TypedKey t
- Data.Json: serialiseJsonBs :: ToJson a => a -> ByteString
- Data.Json: serialiseJsonBsl :: ToJson a => a -> ByteString
- Data.Json: serialiseJsonT :: ToJson a => a -> Text
- Data.Json: toJson :: ToJson a => a -> Value
- Data.Json.Parser: (.->) :: ConstrTagger r => Text -> Parser (ResultType r) -> r
- Data.Json.Parser: (:$:) :: HVectElim ts k -> ObjSpec ts -> ParseSpec k
- Data.Json.Parser: (:&&:) :: !(TypedKey t) -> !(ObjSpec ts) -> ObjSpec (t : ts)
- Data.Json.Parser: (:|:) :: KeyedConstr k -> ParseSpec k -> ParseSpec k
- Data.Json.Parser: (<||>) :: KeyedConstr k -> ParseSpec k -> ParseSpec k
- Data.Json.Parser: FirstConstr :: KeyedConstr k -> ParseSpec k
- Data.Json.Parser: ObjSpecNil :: ObjSpec []
- Data.Json.Parser: WrappedValue :: !t -> WrappedValue
- Data.Json.Parser: class ConstrTagger r where type family ResultType r :: *
- Data.Json.Parser: class JsonReadable t
- Data.Json.Parser: data KeyedConstr k
- Data.Json.Parser: data ObjSpec (ts :: [*])
- Data.Json.Parser: data ParseSpec k
- Data.Json.Parser: data TypedKey t
- Data.Json.Parser: data WrappedValue
- Data.Json.Parser: getOptValueByKey :: (Monad m, Typeable t) => Text -> HashMap Text WrappedValue -> m (Maybe t)
- Data.Json.Parser: getValueByKey :: (Monad m, Typeable t) => Text -> HashMap Text WrappedValue -> m t
- Data.Json.Parser: instance [overlap ok] (JsonReadable a, JsonReadable b) => JsonReadable (Either a b)
- Data.Json.Parser: instance [overlap ok] ConstrTagger (KeyedConstr k)
- Data.Json.Parser: instance [overlap ok] ConstrTagger (ParseSpec k)
- Data.Json.Parser: instance [overlap ok] JsonReadable Bool
- Data.Json.Parser: instance [overlap ok] JsonReadable Double
- Data.Json.Parser: instance [overlap ok] JsonReadable Int
- Data.Json.Parser: instance [overlap ok] JsonReadable Int16
- Data.Json.Parser: instance [overlap ok] JsonReadable Int32
- Data.Json.Parser: instance [overlap ok] JsonReadable Int64
- Data.Json.Parser: instance [overlap ok] JsonReadable Int8
- Data.Json.Parser: instance [overlap ok] JsonReadable Scientific
- Data.Json.Parser: instance [overlap ok] JsonReadable Text
- Data.Json.Parser: instance [overlap ok] JsonReadable Word
- Data.Json.Parser: instance [overlap ok] JsonReadable Word16
- Data.Json.Parser: instance [overlap ok] JsonReadable Word32
- Data.Json.Parser: instance [overlap ok] JsonReadable Word64
- Data.Json.Parser: instance [overlap ok] JsonReadable Word8
- Data.Json.Parser: instance [overlap ok] JsonReadable a => JsonReadable (HVect '[a])
- Data.Json.Parser: instance [overlap ok] JsonReadable t => JsonReadable (Maybe t)
- Data.Json.Parser: instance [overlap ok] JsonReadable t => JsonReadable (Vector t)
- Data.Json.Parser: instance [overlap ok] JsonReadable t => JsonReadable (t, t)
- Data.Json.Parser: instance [overlap ok] JsonReadable t => JsonReadable [t]
- Data.Json.Parser: instance [overlap ok] Typeable t => IsString (TypedKey (Maybe t))
- Data.Json.Parser: instance [overlap ok] Typeable t => IsString (TypedKey t)
- Data.Json.Parser: optKey :: Typeable t => Text -> TypedKey (Maybe t)
- Data.Json.Parser: parseJsonBs :: JsonReadable t => ByteString -> Either String t
- Data.Json.Parser: parseJsonBsl :: JsonReadable t => ByteString -> Either String t
- Data.Json.Parser: parseJsonT :: JsonReadable t => Text -> Either String t
- Data.Json.Parser: readJson :: JsonReadable t => Parser t
- Data.Json.Parser: readObject :: (Text -> Maybe (Parser a)) -> Parser (HashMap Text a)
- Data.Json.Parser: reqKey :: Typeable t => Text -> TypedKey t
- Data.Json.Parser: runParseSpec :: ParseSpec k -> Parser k
- Data.Json.Parser: type Parser = Parser ByteString
- Data.Json.Parser: typedKeyKey :: TypedKey t -> Text
- Data.Json.Serialiser: (.:) :: (ToJson t, Typeable t) => Text -> (k -> t) -> SpecKey k t
- Data.Json.Serialiser: (.:?) :: (ToJson t, Typeable t) => Text -> (k -> Maybe t) -> SpecKey k (Maybe t)
- Data.Json.Serialiser: (.<-) :: ToJson a => Text -> a -> KeyedSerialiser k
- Data.Json.Serialiser: (.=#) :: ToJson a => Addr# -> a -> ObjectBuilder
- Data.Json.Serialiser: (.=) :: ToJson a => Text -> a -> ObjectBuilder
- Data.Json.Serialiser: (:&&&:) :: !(SpecKey k t) -> !(SerObjSpec k ts) -> SerObjSpec k (t : ts)
- Data.Json.Serialiser: MultiConstr :: (k -> KeyedSerialiser k) -> SerSpec k
- Data.Json.Serialiser: SerObjSpecNil :: SerObjSpec k []
- Data.Json.Serialiser: SingleConstr :: SerObjSpec k ts -> SerSpec k
- Data.Json.Serialiser: array :: (Foldable t, ToJson a) => t a -> Value
- Data.Json.Serialiser: class ToJson a
- Data.Json.Serialiser: data KeyedSerialiser k
- Data.Json.Serialiser: data ObjectBuilder :: *
- Data.Json.Serialiser: data SerObjSpec k (ts :: [*])
- Data.Json.Serialiser: data SerSpec k
- Data.Json.Serialiser: data SpecKey k t
- Data.Json.Serialiser: data Value :: *
- Data.Json.Serialiser: emptyObject :: Value
- Data.Json.Serialiser: instance (ToJson a, ToJson b) => ToJson (Either a b)
- Data.Json.Serialiser: instance (ToJson a, ToJson b) => ToJson (a, b)
- Data.Json.Serialiser: instance ToJson Int64
- Data.Json.Serialiser: nullValue :: Value
- Data.Json.Serialiser: row :: (ToJsonString k, ToJson v) => k -> v -> ObjectBuilder
- Data.Json.Serialiser: runSerSpec :: SerSpec k -> k -> Value
- Data.Json.Serialiser: serialiseJsonBs :: ToJson a => a -> ByteString
- Data.Json.Serialiser: serialiseJsonBsl :: ToJson a => a -> ByteString
- Data.Json.Serialiser: serialiseJsonT :: ToJson a => a -> Text
- Data.Json.Serialiser: toJson :: ToJson a => a -> Value
+ Data.HighJson: (.->) :: Text -> Prism' t o -> SumOption t o
+ Data.HighJson: (.=) :: FromJSON f => Text -> (t -> f) -> RecordField t f
+ Data.HighJson: (.=?) :: FromJSON f => Text -> (t -> Maybe f) -> RecordField t (Maybe f)
+ Data.HighJson: BodySpecRecord :: !(RecordSpec a as) -> BodySpec a as
+ Data.HighJson: BodySpecSum :: !(SumSpec a as) -> BodySpec a as
+ Data.HighJson: HighSpec :: !Text -> !(Maybe Text) -> !(BodySpec a as) -> HighSpec a as
+ Data.HighJson: RecordField :: !Text -> !Bool -> (Object -> Text -> Parser f) -> !(t -> f) -> RecordField t f
+ Data.HighJson: RecordSpec :: (HVect fs -> a) -> RecordFields a fs -> RecordSpec a fs
+ Data.HighJson: SumOption :: !Text -> !(Prism' t o) -> SumOption t o
+ Data.HighJson: SumSpec :: SumOptions a os -> SumSpec a os
+ Data.HighJson: [:+:] :: RecordField t f -> RecordFields t fs -> RecordFields t (f : fs)
+ Data.HighJson: [:|:] :: SumOption t o -> SumOptions t os -> SumOptions t (o : os)
+ Data.HighJson: [RFEmpty] :: RecordFields t '[]
+ Data.HighJson: [SOEmpty] :: SumOptions t '[]
+ Data.HighJson: [hs_bodySpec] :: HighSpec a as -> !(BodySpec a as)
+ Data.HighJson: [hs_description] :: HighSpec a as -> !(Maybe Text)
+ Data.HighJson: [hs_name] :: HighSpec a as -> !Text
+ Data.HighJson: [rf_get] :: RecordField t f -> !(t -> f)
+ Data.HighJson: [rf_jsonKey] :: RecordField t f -> !Text
+ Data.HighJson: [rf_jsonLoader] :: RecordField t f -> Object -> Text -> Parser f
+ Data.HighJson: [rf_optional] :: RecordField t f -> !Bool
+ Data.HighJson: [rs_fields] :: RecordSpec a fs -> RecordFields a fs
+ Data.HighJson: [rs_make] :: RecordSpec a fs -> HVect fs -> a
+ Data.HighJson: [so_jsonKey] :: SumOption t o -> !Text
+ Data.HighJson: [so_prism] :: SumOption t o -> !(Prism' t o)
+ Data.HighJson: [ss_options] :: SumSpec a os -> SumOptions a os
+ Data.HighJson: class FromJSON a
+ Data.HighJson: class ToJSON a
+ Data.HighJson: data BodySpec a as
+ Data.HighJson: data HighSpec a as
+ Data.HighJson: data RecordField t f
+ Data.HighJson: data RecordFields t fs
+ Data.HighJson: data RecordSpec a fs
+ Data.HighJson: data SumOption t o
+ Data.HighJson: data SumOptions t os
+ Data.HighJson: data SumSpec a os
+ Data.HighJson: jsonEncoder :: AllHave ToJSON as => HighSpec a as -> a -> Encoding
+ Data.HighJson: jsonParser :: AllHave FromJSON as => HighSpec a as -> Value -> Parser a
+ Data.HighJson: jsonSerializer :: AllHave ToJSON as => HighSpec a as -> a -> Value
+ Data.HighJson: optField :: FromJSON f => Text -> (t -> Maybe f) -> RecordField t (Maybe f)
+ Data.HighJson: parseJSON :: FromJSON a => Value -> Parser a
+ Data.HighJson: parseJSONList :: FromJSON a => Value -> Parser [a]
+ Data.HighJson: recSpec :: Text -> Maybe Text -> HVectElim flds t -> RecordFields t flds -> HighSpec t flds
+ Data.HighJson: reqField :: FromJSON f => Text -> (t -> f) -> RecordField t f
+ Data.HighJson: sumOpt :: Text -> Prism' t o -> SumOption t o
+ Data.HighJson: sumSpec :: Text -> Maybe Text -> SumOptions t flds -> HighSpec t flds
+ Data.HighJson: toEncoding :: ToJSON a => a -> Encoding
+ Data.HighJson: toEncodingList :: ToJSON a => [a] -> Encoding
+ Data.HighJson: toJSON :: ToJSON a => a -> Value
+ Data.HighJson: toJSONList :: ToJSON a => [a] -> Value
Files
- LICENSE +1/−1
- README.md +0/−89
- bench/Twitter.hs +125/−36
- bench/json-data/jp100.json +1/−0
- highjson.cabal +34/−37
- src/Data/HighJson.hs +77/−0
- src/Data/HighJson/Types.hs +153/−0
- src/Data/Json.hs +0/−93
- src/Data/Json/Parser.hs +0/−381
- src/Data/Json/Serialiser.hs +0/−120
- test/Data/Json/ParserSpec.hs +0/−83
- test/Data/JsonSpec.hs +155/−0
- test/Main.hs +9/−1
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2015 Alexander Thiemann <mail@athiemann.net>+Copyright (c) 2015 - 2017 Alexander Thiemann <mail@athiemann.net> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
− README.md
@@ -1,89 +0,0 @@-highjson-=====--[](https://travis-ci.org/agrafix/highjson)--[](http://packdeps.haskellers.com/reverse/highjson)--## Intro--Hackage: [highjson](http://hackage.haskell.org/package/highjson)--Low boilerplate, easy to use and very fast Haskell JSON serialisation and parsing. **WARNING: Work in progress!**--## Usage--```haskell-{-# LANGUAGE OverloadedStrings #-}-data SomeDummy- = SomeDummy- { sd_int :: Int- , sd_bool :: Bool- , sd_text :: T.Text- , sd_either :: Either Bool T.Text- , sd_maybe :: Maybe Int- } deriving (Show, Eq)--someDummySpec =- JsonSpec SomeDummy $- "int" .= sd_int- :+: "bool" .= sd_bool- :+: "text" .= sd_text- :+: "either" .= sd_either- :+: "maybe" .=? sd_maybe- :+: EmptySpec--instance ToJson SomeDummy where- toJson = makeSerialiser someDummySpec--instance JsonReadable SomeDummy where- readJson = makeParser someDummySpec--test =- parseJsonBs "{\"int\": 34, \"text\": \"Teext\", \"bool\": true, \"either\": false}"- == Right (SomeDummy 34 True "Teext" (Left False) Nothing)- ```--For more usage examples check the tests.--## Install--* Using cabal: `cabal install highjson`-* From Source: `git clone https://github.com/agrafix/highjson.git && cd highjson && cabal install`--## Todo--* Implement proper string parsing (handle escape charaters)-* Write more tests-* Generate typescript interfaces from object specs-* ...--## Benchmarks--To run the benchmarks, use `cabal bench`. Current results on my MacBook Pro:--```-$ cabal bench-Preprocessing library highjson-0.2.0.0...-In-place registering highjson-0.2.0.0...-Preprocessing benchmark 'highjson-benchmarks' for highjson-0.2.0.0...-Running 1 benchmarks...-Benchmark highjson-benchmarks: RUNNING...-benchmarking twitter/aeson-time 2.148 ms (2.102 ms .. 2.187 ms)- 0.997 R² (0.995 R² .. 0.999 R²)-mean 2.137 ms (2.112 ms .. 2.169 ms)-std dev 99.12 μs (81.84 μs .. 120.1 μs)-variance introduced by outliers: 31% (moderately inflated)--benchmarking twitter/highjson-time 2.196 ms (2.162 ms .. 2.235 ms)- 0.998 R² (0.996 R² .. 0.999 R²)-mean 2.222 ms (2.195 ms .. 2.252 ms)-std dev 94.52 μs (75.45 μs .. 125.1 μs)-variance introduced by outliers: 28% (moderately inflated)-```--The benchmarks are derived from [aeson](https://github.com/bos/aeson)'s-twitter-json-parsing benchmarks and should probably more there when this library is in a-more complete state.
bench/Twitter.hs view
@@ -3,57 +3,75 @@ -- See https://github.com/bos/aeson -- -{-# LANGUAGE OverloadedStrings, DeriveDataTypeable, DeriveGeneric, ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable, DeriveGeneric, DataKinds, ScopedTypeVariables #-} module Main where +import Control.DeepSeq+import Criterion.Main import Data.Data (Typeable, Data)+import Data.HighJson import Data.Int (Int64) import Data.Text (Text)-import Criterion.Main-import qualified Data.Aeson as A import GHC.Generics (Generic) import Prelude hiding (id)-import Control.DeepSeq-import Data.Json+import qualified Data.Aeson as A+import qualified Data.Aeson.Types as A import qualified Data.ByteString as BS data Metadata = Metadata { result_type :: Text } deriving (Eq, Show, Typeable, Data, Generic) +metadataSpec :: HighSpec Metadata '[Text] metadataSpec =- JsonSpec Metadata $+ recSpec "MetaData" Nothing Metadata $ "result_type" .= result_type- :+: EmptySpec+ :+: RFEmpty -instance JsonReadable Metadata where- readJson = makeParser metadataSpec+instance FromJSON Metadata where+ parseJSON = jsonParser metadataSpec -instance ToJson Metadata where- toJson = makeSerialiser metadataSpec+instance ToJSON Metadata where+ toJSON = jsonSerializer metadataSpec+ toEncoding = jsonEncoder metadataSpec instance NFData Metadata +data Metadata1 = Metadata1 {+ result_type1 :: Text+ } deriving (Eq, Show, Typeable, Data, Generic)++instance NFData Metadata1+ data Geo = Geo { type_ :: Text , coordinates :: (Double, Double) } deriving (Eq, Show, Typeable, Data, Generic) +geoSpec :: HighSpec Geo '[Text, (Double, Double)] geoSpec =- JsonSpec Geo $+ recSpec "Geo" Nothing Geo $ "type_" .= type_ :+: "coordinates" .= coordinates- :+: EmptySpec+ :+: RFEmpty -instance JsonReadable Geo where- readJson = makeParser geoSpec+instance FromJSON Geo where+ parseJSON = jsonParser geoSpec -instance ToJson Geo where- toJson = makeSerialiser geoSpec+instance ToJSON Geo where+ toJSON = jsonSerializer geoSpec+ toEncoding = jsonEncoder geoSpec instance NFData Geo +data Geo1 = Geo1 {+ type_1 :: Text+ , coordinates1 :: (Double, Double)+ } deriving (Eq, Show, Typeable, Data, Generic)++instance NFData Geo1+ data Story = Story { from_user_id_str :: Text , profile_image_url :: Text@@ -71,8 +89,10 @@ , source :: Text } deriving (Show, Typeable, Data, Generic) +storySpec :: HighSpec Story '[Text, Text, Text, Text, Text, Metadata, Maybe Int64, Text, Int64,+ Int64, Maybe Geo, Text, Maybe Text, Text] storySpec =- JsonSpec Story $+ recSpec "Story" Nothing Story $ "from_user_id_str" .= from_user_id_str :+: "profile_image_url" .= profile_image_url :+: "created_at" .= created_at@@ -87,16 +107,35 @@ :+: "iso_language_code" .= iso_language_code :+: "to_user_id_str" .= to_user_id_str :+: "source" .= source- :+: EmptySpec--instance JsonReadable Story where- readJson = makeParser storySpec+ :+: RFEmpty -instance ToJson Story where- toJson = makeSerialiser storySpec+instance FromJSON Story where+ parseJSON = jsonParser storySpec +instance ToJSON Story where+ toJSON = jsonSerializer storySpec+ toEncoding = jsonEncoder storySpec instance NFData Story +data Story1 = Story1 {+ from_user_id_str1 :: Text+ , profile_image_url1 :: Text+ , created_at1 :: Text+ , from_user1 :: Text+ , id_str1 :: Text+ , metadata1 :: Metadata1+ , to_user_id1 :: Maybe Int64+ , text1 :: Text+ , id1 :: Int64+ , from_user_id1 :: Int64+ , geo1 :: Maybe Geo1+ , iso_language_code1 :: Text+ , to_user_id_str1 :: Maybe Text+ , source1 :: Text+ } deriving (Show, Typeable, Data, Generic)++instance NFData Story1+ data Result = Result { results :: [Story] , max_id :: Int64@@ -111,8 +150,10 @@ , query :: Text } deriving (Show, Typeable, Data, Generic) +resultSpec :: HighSpec Result '[[Story], Int64, Int64, Text, Text, Int, Int, Double, Text, Text,+ Text] resultSpec =- JsonSpec Result $+ recSpec "Result" Nothing Result $ "results" .= results :+: "max_id" .= max_id :+: "since_id" .= since_id@@ -124,33 +165,81 @@ :+: "since_id_str" .= since_id_str :+: "max_id_str" .= max_id_str :+: "query" .= query- :+: EmptySpec+ :+: RFEmpty -instance JsonReadable Result where- readJson = makeParser resultSpec+instance FromJSON Result where+ parseJSON = jsonParser resultSpec -instance ToJson Result where- toJson = makeSerialiser resultSpec+instance ToJSON Result where+ toJSON = jsonSerializer resultSpec+ toEncoding = jsonEncoder resultSpec instance NFData Result -instance A.FromJSON Metadata-instance A.FromJSON Geo-instance A.FromJSON Story-instance A.FromJSON Result+data Result1 = Result1 {+ results1 :: [Story1]+ , max_id1 :: Int64+ , since_id1 :: Int64+ , refresh_url1 :: Text+ , next_page1 :: Text+ , results_per_page1 :: Int+ , page1 :: Int+ , completed_in1 :: Double+ , since_id_str1 :: Text+ , max_id_str1 :: Text+ , query1 :: Text+ } deriving (Show, Typeable, Data, Generic) +instance NFData Result1++instance A.FromJSON Metadata1 where+ parseJSON =+ A.genericParseJSON $+ A.defaultOptions+ { A.fieldLabelModifier = \lbl -> take (length lbl - 1) lbl+ }+instance A.FromJSON Geo1 where+ parseJSON =+ A.genericParseJSON $+ A.defaultOptions+ { A.fieldLabelModifier = \lbl -> take (length lbl - 1) lbl+ }+instance A.FromJSON Story1 where+ parseJSON =+ A.genericParseJSON $+ A.defaultOptions+ { A.fieldLabelModifier = \lbl -> take (length lbl - 1) lbl+ }+instance A.FromJSON Result1 where+ parseJSON =+ A.genericParseJSON $+ A.defaultOptions+ { A.fieldLabelModifier = \lbl -> take (length lbl - 1) lbl+ }+ checkOkIs :: Either String Result -> Result checkOkIs lf = case lf of Left errMsg -> error $ "Benchmark failed! " ++ errMsg Right r -> r +checkOkIs1 :: Either String Result1 -> Result1+checkOkIs1 lf =+ case lf of+ Left errMsg -> error $ "Benchmark failed! " ++ errMsg+ Right r -> r+ main :: IO () main = defaultMain [ env (BS.readFile "bench/json-data/twitter100.json") $ \ ~(twitter100 :: BS.ByteString) -> bgroup "twitter"- [ bench "aeson" $ nf (checkOkIs . A.eitherDecodeStrict') twitter100- , bench "highjson" $ nf (checkOkIs . parseJsonBs) twitter100+ [ bench "aeson/generic" $ nf (checkOkIs1 . A.eitherDecodeStrict') twitter100+ , bench "aeson/highjson" $ nf (checkOkIs . A.eitherDecodeStrict') twitter100+ ]+ , env (BS.readFile "bench/json-data/jp100.json") $ \ ~(twitter100 :: BS.ByteString) ->+ bgroup "twitter-jp"+ [ bench "aeson/generic" $ nf (checkOkIs1 . A.eitherDecodeStrict') twitter100+ , bench "aeson/highjson" $ nf (checkOkIs . A.eitherDecodeStrict') twitter100 ] ]
+ bench/json-data/jp100.json view
@@ -0,0 +1,1 @@+{"results":[{"from_user_id_str":"178045354","profile_image_url":"http://a0.twimg.com/profile_images/1214479381/154722_10100141954893059_808622_55276626_7445050_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:40:04 +0000","from_user":"ChuriSta_gt","id_str":"41190705623732224","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3072\u3089\u304c\u306a\u306e\u300c\u3064\u300d\u306f\u3082\u3046Twitter\u306e\u300c\u3064\u300d\u3060\uff01","id":41190705623732224,"from_user_id":178045354,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twipple.jp/" rel="nofollow">\u3064\u3044\u3063\u3077\u308b for iPhone</a>"},{"from_user_id_str":"71746558","profile_image_url":"http://a2.twimg.com/profile_images/591641547/wwd_normal.gif","created_at":"Fri, 25 Feb 2011 17:40:02 +0000","from_user":"fuckkilldiestar","id_str":"41190699571494912","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u306b\u3057\u3066\u3082Twitter\u3084pixiv\u96e2\u308c\u3092\u3069\u3046\u306b\u304b\u3057\u308d\u674f\u4ec1\u30d6\u30eb\u30de","id":41190699571494912,"from_user_id":71746558,"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":"131230176","profile_image_url":"http://a2.twimg.com/sticky/default_profile_images/default_profile_5_normal.png","created_at":"Fri, 25 Feb 2011 17:39:58 +0000","from_user":"proory_bot","id_str":"41190683922546688","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30ea\u30cd\u30f3\u30dd\u30fc\u30c1 http://bit.ly/btjqlH","id":41190683922546688,"from_user_id":131230176,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://proory.com/" rel="nofollow">proory tems</a>"},{"from_user_id_str":"120359038","profile_image_url":"http://a1.twimg.com/profile_images/946521484/200805161826000_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:58 +0000","from_user":"tukinosuke","id_str":"41190680835391488","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @fuefukioyasumi: \u3082\u3046\u3044\u3044\u3002\u300c\u671d\u751f\u300d\u306a\u3093\u304b\u3044\u3044\u3002BBC\u3082CNN\u3082\u82f1\u8a9e\u653e\u9001\u3060\u3002\u307f\u3093\u306a\u3001\u30c6\u30ec\u30d3\u3092\u3076\u3061\u3063\u3068\u5207\u3063\u3066Twitter\u3092\u898b\u3088\u3046\u3002\u3053\u3053\u306b\u300c\u751f\u304d\u305f\u60c5\u5831\u300d\u304c\u6d41\u308c\u3066\u3044\u308b\u3002\u300c\u751f\u304d\u305f\u53eb\u3073\u300d\u304c\u3042\u308b\u3002\u3053\u3053\u304b\u3089\u3067\u3082\u6b74\u53f2\u306e\u8ee2\u63db\u70b9\u3092\u611f\u3058\u308b\u4e8b\u304c\u3067\u304d\u308b\u306e\u3060\u3002 @gjmorley #libjp","id":41190680835391488,"from_user_id":120359038,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"166512109","profile_image_url":"http://a3.twimg.com/profile_images/1224583217/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:50 +0000","from_user":"yurii1129","id_str":"41190649839620096","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4eca\u6c17\u4ed8\u3044\u305f\u2026\u307f\u3043\u304f\u3093\u306eTwitter\u540d\u3001\u3084\u307e\u306d\u3084\u3093(\uffe3\u25c7\uffe3;)","id":41190649839620096,"from_user_id":166512109,"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":"228999619","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_6_normal.png","created_at":"Fri, 25 Feb 2011 17:39:49 +0000","from_user":"takami926","id_str":"41190644793745408","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u7530\u539f\u3055\u3093\u3001\u5fdc\u63f4\u3057\u3066\u307e\u3059\u3002WEB\u3082TWITTER\u3082\u62dd\u898b\u3057\u3066\u307e\u3059\u3002\u7530\u539f\u3055\u3093\u304c\u653f\u6cbb\u5bb6\u306b\u306a\u3063\u3066\u3001\u65e5\u672c\u3092\u5909\u3048\u3066\u304f\u3060\u3055\u3044\u3002\u5c16\u95a3\u3001\u5317\u65b9\u554f\u984c\u5171\u306b\u65e5\u672c\u306e\u653f\u6cbb\u306e\u5931\u6557\u3067\u3059\u3002\u8a55\u8ad6\u5bb6\u306f\u8272\u3005\u8a00\u3063\u3066\u307e\u3059\u304c\u3001\u4e2d\u6771\u307b\u3069\u56fd\u6c11\u306e\u71b1\u6c17\u304c\u7121\u304f\u3001\u683c\u5dee\u304c\u3042\u308a\u3001\u4f55\u3082\u5909\u308f\u3089\u306a\u3044\u666f\u6c17\u4f4e\u8ff7\u306e\u65e5\u672c\u306b\u56fd\u6c11\u306f\u8ae6\u3081\u3066\u308b\u3093\u3067\u3059\u3002","id":41190644793745408,"from_user_id":228999619,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"151773701","profile_image_url":"http://a0.twimg.com/profile_images/1213699753/obi_nao_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:44 +0000","from_user":"obi_nao","id_str":"41190622949941248","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3060\u3044\u3076\u5e74\u4e0b\u306e\u5f8c\u8f29\u306b\u3001\u30d3\u30b8\u30cd\u30b9\u3084\u308b\u306a\u3089\u771f\u5263\u306bTwitter\u3084\u308c\uff01\u3063\u3066\u6012\u3089\u308c\u305f\u3002\u306a\u306e\u3067\u4eca\u65e5\u304b\u3089\u771f\u5263\u306b\u3064\u3076\u3084\u304f\u3053\u3068\u306b\u3057\u307e\u3059\u3002\u3088\u308d\u3057\u304f\u3067\u3059\u3002","id":41190622949941248,"from_user_id":151773701,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.flight.co.jp/iPhone/TweetMe/" rel="nofollow">TweetMe for iPhone</a>"},{"from_user_id_str":"20817229","profile_image_url":"http://a0.twimg.com/profile_images/1212012721/205_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:43 +0000","from_user":"allte","id_str":"41190619804082176","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u7206\u7b11\u3057\u3066\u547c\u5438\u56f0\u96e3\u3067\u75d9\u6523\u3059\u308b\u5618\u304f\u3093\u304c\u898b\u308c\u308b\u306e\u306fTwitter\u3060\u3051","id":41190619804082176,"from_user_id":20817229,"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":"166907967","profile_image_url":"http://a2.twimg.com/profile_images/1250526230/___normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:43 +0000","from_user":"NTTYAHOOOOOOOI","id_str":"41190618235412480","metadata":{"result_type":"recent"},"to_user_id":106469594,"text":"@takahirororo \u3066\u304b\u4f55\u3067twitter\u4e0a\u3067\u30a2\u30c9\u30d0\u30a4\u30b9\u3082\u3089\u3063\u3066\u3093\u306d\u3093\uff57","id":41190618235412480,"from_user_id":166907967,"to_user":"takahirororo","geo":null,"iso_language_code":"ja","to_user_id_str":"106469594","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"82581287","profile_image_url":"http://a0.twimg.com/profile_images/774721566/miyaru2_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:38 +0000","from_user":"kine_rahchaos","id_str":"41190598132244480","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30a2\u30aa\u30b7\u30de\u3055\u3093\u304cTwitter\u59cb\u3081\u305f\u3060\u3068\u2026","id":41190598132244480,"from_user_id":82581287,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sourceforge.jp/projects/tween/wiki/FrontPage" rel="nofollow">Tween</a>"},{"from_user_id_str":"136633905","profile_image_url":"http://a2.twimg.com/profile_images/1247161991/yama_normal.png","created_at":"Fri, 25 Feb 2011 17:39:35 +0000","from_user":"yamachi39","id_str":"41190584706285568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3084\u3063\u3071\u308amixi\u3088\u308atwitter\u306e\u304c\u597d\u304d\u304b\u3082","id":41190584706285568,"from_user_id":136633905,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://jigtwi.jp/?p=1" rel="nofollow">jigtwi</a>"},{"from_user_id_str":"44029295","profile_image_url":"http://a2.twimg.com/profile_images/1112965522/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:32 +0000","from_user":"no2yosee","id_str":"41190572769280000","metadata":{"result_type":"recent"},"to_user_id":97721124,"text":"@hn0345 \u3042\u3001\u500b\u4eba\u7684\u306b\u306f\u4eca\u306ftwitter\u306e\u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\u306b\u66f8\u3044\u3066\u3042\u308b\u30d6\u30ed\u30b0\u306e\u30e6\u30cb\u30c3\u30c8\u3092\u306e\u3093\u3073\u308a\u3084\u3063\u3066\u307e\u3059w","id":41190572769280000,"from_user_id":44029295,"to_user":"hn0345","geo":null,"iso_language_code":"ja","to_user_id_str":"97721124","source":"<a href="http://www.flight.co.jp/iPhone/TweetMe/" rel="nofollow">TweetMe for iPhone</a>"},{"from_user_id_str":"149872179","profile_image_url":"http://a0.twimg.com/profile_images/1145770150/Winter11_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:31 +0000","from_user":"xmyyyxx","id_str":"41190566951653376","metadata":{"result_type":"recent"},"to_user_id":95069405,"text":"@rindofu \u653b\u7565\u672c\u3042\u308c\u3070\u3044\u3044\u306e\u306b\u3063\u3066\u601d\u3044\u307e\u3059(T\u03c9T)/~~~ \u79c1\u3082\u76f4\u3057\u305f\u3044\u3068\u3053\u3044\u3063\u3071\u3044\u3060\u3051\u3069\u3001\u3042\u306860\u5e74\u304f\u3089\u3044\u3044\u304d\u3089\u308c\u308b\u306f\u305a\u3060\u3057\u3001\u306e\u3093\u3073\u308a\u76f4\u308c\u3070\u3044\u3044\u306a\u3042 \u304a\u3084\u3059\u307f\u3067\u3059^^\uff01\u308a\u3093\u3055\u3093\u3068twitter\u3067\u4ef2\u826f\u304f\u306a\u308c\u3066\u3088\u304b\u3063\u305f\u3067\u3059\u3063","id":41190566951653376,"from_user_id":149872179,"to_user":"rindofu","geo":null,"iso_language_code":"ja","to_user_id_str":"95069405","source":"<a href="http://twtr.jp" rel="nofollow">Keitai Web</a>"},{"from_user_id_str":"105579892","profile_image_url":"http://a0.twimg.com/profile_images/1212950455/love_happy_pink_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:30 +0000","from_user":"love_happy_pink","id_str":"41190566494601216","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u305d\u308c\u898b\u305f\u3044\u306a\u266aRT @kazukt \u3046\u308b\u304a\u307c\u7d75\u3001\u4ed6\u306e\u4eba\u306e\u3082\u898b\u3066\u3044\u305f\u3089\u3084\u305f\u3089\u30de\u30f3\u30ac\u306e\u30ad\u30e3\u30e9\u30af\u30bf\u30fc\u3067\u3080\u3061\u3083\u304f\u3061\u3083\u4e0a\u624b\u3044\u4eba\u304c\uff01\u2026\u3068\u3001\u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\u898b\u305f\u3089\u3001\u306a\u3093\u3068\u3054\u672c\u4eba\u304c\u66f8\u3044\u3066\u3044\u3089\u3063\u3057\u3083\u3063\u305f\u3002Twitter\u3063\u3066\u30b9\u30b4\u30a4\u308f\u3002","id":41190566494601216,"from_user_id":105579892,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.nibirutech.com/" rel="nofollow">TwitBird iPad</a>"},{"from_user_id_str":"16996368","profile_image_url":"http://a0.twimg.com/profile_images/1198892387/pochi_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:30 +0000","from_user":"HyoYoshikawa","id_str":"41190564187611136","metadata":{"result_type":"recent"},"to_user_id":1800565,"text":"@shinichiro_beck \u73fe\u5730\u304b\u3089\u306a\u3089\u826f\u304f\u3066\u4ed6\u306e\u5730\u57df\u304b\u3089\u3060\u4f59\u8a08\u306a\u3089\u3001\u4f55\u306e\u305f\u3081\u306bTwitter\u304c\u3042\u308b\u306e\u304b\u308f\u304b\u3089\u306a\u3044\u3088\u3002\u3044\u307e\u8d77\u304d\u3066\u308b\u3053\u3068\u306e\u8aac\u660e\u3082\u3064\u304b\u306a\u3044\u3002\u30a2\u30eb\u30b8\u30e3\u30b8\u30fc\u30e9\u304c\u4f1d\u3048\u3066\u308b\u3053\u3068\u304c\u5168\u3066\u3058\u3083\u306a\u3044\u3057\u3001\u65e5\u672c\u306eTV\u306f\u4f1d\u3048\u306a\u3044\u3067\u3057\u3087\u3046\u3002\u77e5\u308a\u305f\u304c\u3063\u3066\u308b\u4eba\u3082\u305f\u304f\u3055\u3093\u3044\u308b\u3002","id":41190564187611136,"from_user_id":16996368,"to_user":"shinichiro_beck","geo":null,"iso_language_code":"ja","to_user_id_str":"1800565","source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"119070802","profile_image_url":"http://a2.twimg.com/profile_images/1229773005/346d8435099798113a1326e1ba4949ee_normal.jpeg","created_at":"Fri, 25 Feb 2011 17:39:25 +0000","from_user":"takotako726","id_str":"41190545439207424","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u9b54\u6cd5\u5c11\u5973\u307e\u3069\u304b\u30de\u30ae\u30ab\u306e\u53cd\u97ff\u304ctwitter\u3067\u306f\u3093\u3071\u306d\u3048\u4ef6\u3002","id":41190545439207424,"from_user_id":119070802,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://z.twipple.jp/" rel="nofollow">\u3064\u3044\u3063\u3077\u308b/twipple</a>"},{"from_user_id_str":"165695316","profile_image_url":"http://a1.twimg.com/profile_images/681748782/ring_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:21 +0000","from_user":"pandora_shotbar","id_str":"41190526447390720","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u300e\u30b7\u30e7\u30c3\u30c8\u30d0\u30fc\u3000\u30d1\u30f3\u30c9\u30e9\u3000\u30c4\u30a4\u30c3\u30bf\u30fc\u306e\u3064\u3076\u3084\u304d\u300f\u30b7\u30e7\u30c3\u30c8\u30d0\u30fc\u3000\u30d1\u30f3\u30c9\u30e9\u3000\u30c4\u30a4\u30c3\u30bf\u30fc\u306e\u3064\u2026\uff5chttp://pandora-twitter.seesaa.net/article/187809936.html","id":41190526447390720,"from_user_id":165695316,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://blog.seesaa.jp/" rel="nofollow">SeesaaBlog</a>"},{"from_user_id_str":"88862311","profile_image_url":"http://a2.twimg.com/profile_images/1182243698/161113_100001897885617_169366_q_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:16 +0000","from_user":"amebaguide","id_str":"41190504926416896","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u300e\u30a2\u30e1\u30d6\u30ed\u653b\u7565\u30ac\u30a4\u30c9\u306e\u30c4\u30a4\u30c3\u30bf\u30fc\u306e\u3064\u3076\u3084\u304d\u300f\u30d6\u30ed\u30b0\u306e\u653b\u7565\u3000\u30c4\u30a4\u30c3\u30bf\u30fc\u306e\u3064\u3076\u3084\u304d\u96c6\uff5chttp://accessup-twitter.seesaa.net/article/187809931.html","id":41190504926416896,"from_user_id":88862311,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://blog.seesaa.jp/" rel="nofollow">SeesaaBlog</a>"},{"from_user_id_str":"186895007","profile_image_url":"http://a2.twimg.com/profile_images/1229610799/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:11 +0000","from_user":"zizikt","id_str":"41190486123356161","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3053\u308c\u306f\u500b\u4eba\u7684\u306b\u306f\u91cd\u5b9d\u3067\u3059\u3002\n\u25c6iPhone&iPad\u5411\u3051Twitter\u30a2\u30d7\u30ea\u300c\u3064\u3044\u3063\u3077\u308b\u300d\u306bEvernote\u3068\u306e\u9023\u643a\u6a5f\u80fd\u3092\u8ffd\u52a0 \nhttp://bit.ly/hPf44u","id":41190486123356161,"from_user_id":186895007,"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":"132320738","profile_image_url":"http://a3.twimg.com/profile_images/1229760475/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:04 +0000","from_user":"faina_","id_str":"41190453592334336","metadata":{"result_type":"recent"},"to_user_id":167894537,"text":"@gjmorley \u30e2\u30fc\u30ea\u30fc\u3055\u3093\u306e\u7ffb\u8a33\u306e\u8a00\u8449\u306e\u30bb\u30f3\u30b9\u304c\u3059\u304d\u3067\u3059\u3002\u305d\u3057\u3066\u3001Twitter\u3067\u77e5\u308b\u3001\u73fe\u5730\u306e\u4eba\u306e\u76ee\u306e\u529b\u3084\u3001\u60c5\u5831\u3092\u4f1d\u3048\u3066\u304f\u308c\u308b\u7686\u3055\u3093\u306e\u60c5\u71b1\u306b\u611f\u52d5\u3057\u3066\u3044\u307e\u3059\u3002\u611f\u52d5\u3059\u308b\u3063\u3066\u3059\u3054\u3044\u30a8\u30cd\u30eb\u30ae\u30fc\u3067\u3059\uff01\uff01","id":41190453592334336,"from_user_id":132320738,"to_user":"gjmorley","geo":null,"iso_language_code":"ja","to_user_id_str":"167894537","source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"24870552","profile_image_url":"http://a3.twimg.com/profile_images/907130634/4_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:03 +0000","from_user":"tana1192","id_str":"41190450480021504","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u500b\u4eba\u7684\u306b\u306f\u3001\u30bf\u30b0\u5f3e\u304d\u3059\u308c\u3070\u3044\u3044\uff08\u5f3e\u3051\u308b\u30c4\u30fc\u30eb\u3092\u4f7f\u3063\u3066Twitter\u3092\u3059\u308c\u3070\u3044\u3044\uff09\u3068\u601d\u3046\u3093\u3060\u3051\u3069\u306a\u3042\u3002\u307f\u3093\u306a\u305d\u308c\u306a\u308a\u306bTwitter\u3084\u308b\u4eba\u3060\u3057\u3001\u30c4\u30fc\u30eb\u9078\u3073\u304f\u3089\u3044\u5e45\u3092\u6301\u3063\u3066\u3084\u3063\u3066\u3082\u3002 \u307e\u3042\u3001\u4ffa\u30a2\u30cb\u30e1\u306f\u89b3\u308b\u89b3\u308b\u8a50\u6b3a\u3059\u308b\u3060\u3051\u306e\u4eba\u3060\u304b\u3089\u95a2\u4fc2\u306a\u3044\u3093\u3060\u3051\u3069\u3082\uff57\uff57\u5b9f\u6cc1\u306f\u697d\u3057\u305d\u3046\u306b\u898b\u3048\u308b\u3088\u3002","id":41190450480021504,"from_user_id":24870552,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sourceforge.jp/projects/tween/wiki/FrontPage" rel="nofollow">Tween</a>"},{"from_user_id_str":"58509646","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Fri, 25 Feb 2011 17:39:02 +0000","from_user":"kakuyas","id_str":"41190446663344128","metadata":{"result_type":"recent"},"to_user_id":107076877,"text":"@Dayspool \u6df1\u591c\uff12\uff19\u6642\u304f\u3089\u3044\u307e\u3067\u306f\u6bce\u65e5\u55b6\u696d\u3057\u3066\u308b\u306e\u3067\u3001twitter\u3001\u30e1\u30c3\u30bb\u3001PS3\u306a\u3069\u3067\u3088\u3093\u3067\u3051\u308c\u3002\u3053\u3063\u3061\u304b\u3089\u58f0\u304b\u3051\u308b\u3053\u3068\u3082\u3042\u308b\u304b\u3082\u3060\u304c\uff57","id":41190446663344128,"from_user_id":58509646,"to_user":"Dayspool","geo":null,"iso_language_code":"ja","to_user_id_str":"107076877","source":"<a href="http://cheebow.info/chemt/archives/2007/04/twitterwindowst.html" rel="nofollow">Twit for Windows</a>"},{"from_user_id_str":"149128527","profile_image_url":"http://a2.twimg.com/profile_images/1254922702/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:39:00 +0000","from_user":"uni13yoki","id_str":"41190437087748096","metadata":{"result_type":"recent"},"to_user_id":119468594,"text":"@kuro_wr84 \u304a\u308c\u3068\u304a\u524d\u3067Twitter\u3067\u4f1a\u8a71\u3057\u305f\u3089\u3001\u5927\u5909\u306a\u3053\u3068\u306b\u306a\u308b\u306a","id":41190437087748096,"from_user_id":149128527,"to_user":"kuro_wr84","geo":null,"iso_language_code":"ja","to_user_id_str":"119468594","source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"18670595","profile_image_url":"http://a2.twimg.com/profile_images/1250674062/ProfilePhoto_normal.png","created_at":"Fri, 25 Feb 2011 17:38:59 +0000","from_user":"nyuuuuun","id_str":"41190436450222080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3078\u30fc\u3053\u3093\u306a\u306b\u3088\u304f\u4f3c\u308b\u3053\u3068\u3082\u3042\u308b\u3093\u3060\u30fc\nhttp://twitter.com/Re_44/status/35943233016168448\nhttp://twitter.com/3510_misaka/status/36122114821988352","id":41190436450222080,"from_user_id":18670595,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"96267603","profile_image_url":"http://a3.twimg.com/profile_images/1245253473/DSiLL3_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:59 +0000","from_user":"arivis","id_str":"41190433119940608","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://twitter.com/#!/arivis/status/40636755380142080 \u306a\u3093\u3064\u3046\u304b\u3053\u308c\u3067\u8d64\u3063\u3066\u306e\u3082\u3061\u3087\u3063\u3068\u3042\u308c\u3063\u3059\u306d\u3002\u305d\u3057\u3066\u4e88\u671f\u3057\u3066\u3044\u305f\u304b\u306e\u3088\u3046\u3060","id":41190433119940608,"from_user_id":96267603,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"148097776","profile_image_url":"http://a3.twimg.com/profile_images/1166904064/broken-heart_normal.png","created_at":"Fri, 25 Feb 2011 17:38:56 +0000","from_user":"ReajuBreaker_A","id_str":"41190422135058432","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u672c\u57a2\u30d5\u30a9\u30ed\u30fc\u3088\u308d\u3057\u304f\u3067\u3059\u2192 http://twitter.com/ReajuBreaker \uff08\uff20\u3060\u3068\u30ea\u30d7\u30e9\u30a4\u304c\u57cb\u307e\u308b\u305f\u3081\u3001URL\u306b\u3057\u3066\u3042\u308a\u307e\u3059\uff09","id":41190422135058432,"from_user_id":148097776,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.twitter.com/ReajuBreaker" rel="nofollow">\u73fe\u5145\u6bba\u3057\u306e\u7121\u4eba\u9023\u545f\uff1c\u30aa\u30fc\u30c8\u30c4\u30a4\u30fc\u30c8\uff1e</a>"},{"from_user_id_str":"59711654","profile_image_url":"http://a2.twimg.com/profile_images/416212928/flowers-06-1_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:56 +0000","from_user":"agamo45","id_str":"41190421522546688","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @ebizo66: \u30ea\u30d3\u30a2\u30fb\u30c8\u30ea\u30dd\u30ea\u306eTw\uff1a\u6551\u6025\u8eca\u304c\u6765\u305f\u304c\u3001\u8ca0\u50b7\u8005\u3092\u8eca\u5185\u3067\u6bba\u5bb3\u3057\u3066\u3044\u305f\u3001\u3068\u3002\uff08\u6ec5\u8336\u82e6\u8336\u3060\uff01\uff09http://ow.ly/43pQ2 #libjp","id":41190421522546688,"from_user_id":59711654,"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":"145311373","profile_image_url":"http://a3.twimg.com/profile_images/1187802576/a_gam_02_normal.png","created_at":"Fri, 25 Feb 2011 17:38:55 +0000","from_user":"nogic1008","id_str":"41190418141937664","metadata":{"result_type":"recent"},"to_user_id":88117317,"text":"@runasoru \u307e\u3042\u5acc\u306a\u3089\u6df1\u591c\u5e2f\u306bTwitter\u898b\u306a\u304d\u3083\u3044\u3044\u3060\u3051\u3067\u3059\u304b\u3089\u306d\u30fc \u30103/19BDM\u30aa\u30d5http://twvt.us/bdoff_kansai\u3011","id":41190418141937664,"from_user_id":145311373,"to_user":"runasoru","geo":null,"iso_language_code":"ja","to_user_id_str":"88117317","source":"<a href="http://sourceforge.jp/projects/tween/wiki/FrontPage" rel="nofollow">Tween</a>"},{"from_user_id_str":"195851300","profile_image_url":"http://a2.twimg.com/profile_images/1124572815/be7b4c0a06cb60e8_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:49 +0000","from_user":"LoveLAscrewDoll","id_str":"41190391147540480","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @jp_mjp: SCREW TV SHOW Vol.6\u306e\u653e\u9001\u304c\u7121\u4e8b\u306b\u7d42\u4e86\u3044\u305f\u3057\u307e\u3057\u305f\u3002\u3054\u89a7\u9802\u304d\u3042\u308a\u304c\u3068\u3046\u3054\u3056\u3044\u307e\u3057\u305f\uff01\u6b21\u56de\u653e\u9001\u306f3\u670818\u65e5(\u91d1)\u3067\u3059\u3002\u8996\u8074\u8005\u30d7\u30ec\u30bc\u30f3\u30c8\u306e\u8a73\u7d30\u306f\u5f8c\u65e5MJP\u3067\u304a\u77e5\u3089\u305b\u3044\u305f\u3057\u307e\u3059\u3002\u305d\u306e\u969b\u306b\u306f\u3001\u3053\u306eTwitter\u3067\u3082\u304a\u77e5\u3089\u305b\u3044\u305f\u3057\u307e\u3059\u306e\u3067\u3001\u304a\u697d\u3057\u307f\u306b\uff01#SCREWTV","id":41190391147540480,"from_user_id":195851300,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://z.twipple.jp/" rel="nofollow">\u3064\u3044\u3063\u3077\u308b/twipple</a>"},{"from_user_id_str":"178045354","profile_image_url":"http://a0.twimg.com/profile_images/1214479381/154722_10100141954893059_808622_55276626_7445050_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:48 +0000","from_user":"ChuriSta_gt","id_str":"41190389549510656","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3053\u3053\u4e00\u9031\u9593Twitter\u304c\u3084\u305f\u3089\u697d\u3057\u3044\u306e\u3067\u3059\u3051\u3069\u30fc\u30fc\u30fc\uff01\u306b\u3072\u3072\u3063\u7b11","id":41190389549510656,"from_user_id":178045354,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twipple.jp/" rel="nofollow">\u3064\u3044\u3063\u3077\u308b for iPhone</a>"},{"from_user_id_str":"50592111","profile_image_url":"http://a0.twimg.com/profile_images/1252176582/lFjpi_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:48 +0000","from_user":"crowNeko","id_str":"41190387271864320","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30a8\u30ed\u30b2\u30d7\u30ec\u30a4\u3057\u306a\u304c\u3089\u307e\u3069\u30de\u30aeTL\u3092\u898b\u306a\u3044\u3088\u3046\u306b\u534a\u76ee\u306b\u306a\u308a\u306a\u304c\u3089Twitter\u3057\u3066\u308b\u6df1\u591c2\u6642\u534a\u3002","id":41190387271864320,"from_user_id":50592111,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://stone.com/Twittelator" rel="nofollow">Twittelator</a>"},{"from_user_id_str":"7141467","profile_image_url":"http://a3.twimg.com/profile_images/1198540741/icon12912579345276_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:40 +0000","from_user":"hina_geshi","id_str":"41190355961380864","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u7d50\u5c40\u30cd\u30bf\u30d0\u30ec\u3059\u3093\u306a\u3063\u3066\u8a00\u3046\u65b9\u304c\u30a2\u30ec\u3060\u3088\u306d\u3001\u3057\u306a\u3044\u308f\u3051\u7121\u3044\u3058\u3083\u306a\u3044\u8133\u5185\u5782\u308c\u6d41\u3057\u304cTwitter\u306a\u3093\u3060\u304b\u3089\u3055","id":41190355961380864,"from_user_id":7141467,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://projects.playwell.jp/go/Saezuri" rel="nofollow">Saezuri</a>"},{"from_user_id_str":"149608984","profile_image_url":"http://a0.twimg.com/profile_images/1205950885/090702_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:39 +0000","from_user":"Mr_Tsubaki","id_str":"41190349447774208","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u307e\u3069\u304b\u306fTwitter\u5408\u308f\u305b\u3066\uff11\u6642\u9593\u306f\u697d\u3057\u3044","id":41190349447774208,"from_user_id":149608984,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://z.twipple.jp/" rel="nofollow">\u3064\u3044\u3063\u3077\u308b/twipple</a>"},{"from_user_id_str":"122271550","profile_image_url":"http://a0.twimg.com/profile_images/961936499/neoneko_bot5jpg_____normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:39 +0000","from_user":"neoneko_bot5","id_str":"41190348726345728","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3010\u30c6\u30b9\u30c8\uff1a23\u3011\u4eca\u65e5\u304b\u3089\u5ba3\u4f1d\u958b\u59cb\u2606\u306d\u304a\u306d\u3053\u306eTwitter \u3067 EasyBottex\u3000\u3067\u304d\u308b\u307e\u3067\uff01\u2192http://neoneko.blog31.fc2.com/","id":41190348726345728,"from_user_id":122271550,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www20.atpages.jp/neoneko/" rel="nofollow">neoneko_bot5</a>"},{"from_user_id_str":"127069188","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_6_normal.png","created_at":"Fri, 25 Feb 2011 17:38:37 +0000","from_user":"MYCHEBOT","id_str":"41190340908163074","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30eb\u30d5\u3055\u3093\u304c\u914d\u4fe1\u3092\u7d42\u4e86\u3057\u307e\u3057\u305f\uff01/ http://777labo.com/mychecker/view/745.php / \u30c8\u30d4\u30c3\u30af:XSplit\u30c6\u30b9\u30c8\u3000twitter\u2192http://twitter.com/rukh01","id":41190340908163074,"from_user_id":127069188,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://777labo.com/mychecker/" rel="nofollow">MYCHEBOT</a>"},{"from_user_id_str":"107626142","profile_image_url":"http://a1.twimg.com/profile_images/1104968421/SuperMaika1_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:34 +0000","from_user":"MaikaPaPa","id_str":"41190328614666240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"75\u5e74\u524d\u306e\u4eca\u65e52\u670826\u65e5\u672a\u660e\u3001\u82e5\u304d\u9752\u5e74\u5c06\u6821\u3089\u304c\u653f\u6cbb\u8150\u6557\u3068\u8fb2\u6751\u306e\u56f0\u7aae\u306b\u5bfe\u3057\u3066\u6c7a\u8d77\u3057\u307e\u3057\u305f\u3002\u3082\u3061\u308d\u3093\u5f53\u6642\u306fTwitter\u3082FB\u3082\u3001\u307e\u305f\u5f53\u7136\u306a\u304c\u3089Internet\u3082\u3042\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u4e00\u65b9\u3001\u30c1\u30e5\u30cb\u30b8\u30a2\u3001\u30a8\u30b8\u30d7\u30c8\u3001\u4e2d\u6771\u306b\u5e83\u304c\u308b\u53cd\u653f\u5e9c\u30c7\u30e2\u3068\u5f37\u6a29\u4f53\u5236\u306e\u5d29\u58ca\u3002\u73fe\u5728\u306e\u65e5\u672c\u3067\u306f\u8003\u3048\u3089\u308c\u306a\u3044\u3053\u3068\u3067\u3059\u3002","id":41190328614666240,"from_user_id":107626142,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"11111695","profile_image_url":"http://a1.twimg.com/sticky/default_profile_images/default_profile_0_normal.png","created_at":"Fri, 25 Feb 2011 17:38:28 +0000","from_user":"kumatchipooh","id_str":"41190306145775617","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @inosenaoki: \u306a\u308b\u307b\u3069\u306d\u3002 RT @dansrmz @inosenaoki \u3053\u3061\u3089\u304c\u30bd\u30d5\u30c8\u30d0\u30f3\u30af\u526f\u793e\u9577\u306e\u677e\u672c\u5fb9\u4e09\u3055\u3093\u306e\u3001Twitter\u306b\u95a2\u3059\u308b\u8ad6\u8003\u3067\u3059\u3002 \u25b6 "Twitter\u306e2\u30c1\u30e3\u30f3\u30cd\u30eb\u5316\u306f\u9632\u6b62\u51fa\u6765\u308b\u304b" http://t.co/Mwzb8Zf","id":41190306145775617,"from_user_id":11111695,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"212161909","profile_image_url":"http://a1.twimg.com/profile_images/1252895790/natm01_normal.gif","created_at":"Fri, 25 Feb 2011 17:38:28 +0000","from_user":"n34hitman","id_str":"41190303830511616","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Twitter\u30fb\u30d6\u30ed\u30b0\u30a2\u30d5\u30a3\u30ea\u30a8\u30a4\u30c8\u81ea\u52d5\u6295.... http://goo.gl/a4RHB 4054","id":41190303830511616,"from_user_id":212161909,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twibow.net/" rel="nofollow">Twibow</a>"},{"from_user_id_str":"105945593","profile_image_url":"http://a2.twimg.com/sticky/default_profile_images/default_profile_5_normal.png","created_at":"Fri, 25 Feb 2011 17:38:24 +0000","from_user":"nakano_bot","id_str":"41190285710983168","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3053\u306ebot\u306f\u4e0d\u52d5\u7523\u4f1a\u793e\u69d8\u5411\u3051\u306e\u4e0d\u52d5\u7523\u30dd\u30fc\u30bf\u30eb\u30b5\u30a4\u30c8\u3078\u306e\u4e00\u62ec\u8ee2\u9001\uff0bTwitter\u7121\u6599\u8ee2\u9001\u30b5\u30fc\u30d3\u30b9\u306b\u3088\u308a\u3064\u3076\u3084\u304d\u307e\u3059\u3002\u3054\u5229\u7528\u306b\u306a\u308a\u305f\u3044\u5834\u5408\u306f http://bit.ly/demey0 \u306b\u304a\u6c17\u8efd\u306b\u304a\u554f\u3044\u5408\u308f\u305b\u4e0b\u3055\u3044\u3002","id":41190285710983168,"from_user_id":105945593,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.teramax.jp/aboutus.html" rel="nofollow">tmxbot</a>"},{"from_user_id_str":"170904226","profile_image_url":"http://a2.twimg.com/profile_images/1249020397/1789kb_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:21 +0000","from_user":"1789kb","id_str":"41190274428305408","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3068\u308a\u3042\u3048\u305a\u4eca\u56de\u521d\u3081\u3066\u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u3067\u898b\u3066\u308f\u304b\u3063\u305f\u306e\u306f\u3001QB\u306f\u5168\u8eab\u304c\u30a2\u30f3\u30d1\u30f3\u30bf\u30a4\u30d7\u3060\u3068\u3044\u3046\u3053\u3068\u3068\u3001\u307e\u3069\u30de\u30ae\u7d42\u4e86\u5f8c\u306eTwitter\u306e\u3056\u308f\u3064\u304d\u304c\u3059\u3054\u3044\u3068\u3044\u3046\u3053\u3068","id":41190274428305408,"from_user_id":170904226,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"166169644","profile_image_url":"http://a1.twimg.com/profile_images/1217017679/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:18 +0000","from_user":"Okkkkkkkkkkun","id_str":"41190262420017152","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3063\u3066Twitter\u3067\u3064\u3076\u3084\u304f\u81ea\u5206\u3082\u76f8\u5f53\u5c0f\u3055\u3044\u306a\u3002","id":41190262420017152,"from_user_id":166169644,"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":"196623456","profile_image_url":"http://a3.twimg.com/profile_images/1219076661/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:06 +0000","from_user":"NoMoneyClub","id_str":"41190213342601216","metadata":{"result_type":"recent"},"to_user_id":195462431,"text":"@yosal15 \nTwitter\u3084\u3063\u3066\u308b\u3089\u3057\u3044\u3002\u3051\u3069\u3001\u898b\u3064\u304b\u3089\u306a\u3044\u3002","id":41190213342601216,"from_user_id":196623456,"to_user":"yosal15","geo":null,"iso_language_code":"ja","to_user_id_str":"195462431","source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"126984048","profile_image_url":"http://a3.twimg.com/profile_images/1254579571/zipyaru-20090829-23-0012_normal.png","created_at":"Fri, 25 Feb 2011 17:38:02 +0000","from_user":"minaduki_naduki","id_str":"41190196418584576","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u203b\u30e1\u30fc\u30eb\u3067\u5973\u306e\u5b50\u53e3\u8aac\u304f\u306e\u306b\u5fd9\u3057\u3044\u3093\u3060\u305d\u3046\u3067\u3059\u3000\u307e\u3058\u3058\u3054\u308d RT @yowano_k: \u5fd9\u3057\u304f\u3066\u3082Twitter\u306b\u9854\u3092\u51fa\u3057\u305f\u304f\u306a\u308b\u50d5\u30a7\u2026\u2026","id":41190196418584576,"from_user_id":126984048,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://seesmic.com/seesmic_desktop/sd2" rel="nofollow">Seesmic Desktop</a>"},{"from_user_id_str":"200568705","profile_image_url":"http://a3.twimg.com/profile_images/1242179765/101230_1355_01_normal.jpg","created_at":"Fri, 25 Feb 2011 17:38:01 +0000","from_user":"hammerstrap","id_str":"41190190428979200","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6628\u65e5\u91d1\u66dc\u65e5\u306f\u732e\u8840\u306b\u5f80\u304f\u3002\u4eca\u306e\u50d5\u306e\u4eba\u9593\u3068\u3057\u3066\u306e\u4fa1\u5024\u306f\u3001\u7cbe\u3005\u3053\u306e\u7a0b\u5ea6\u3002\u8179\u304c\u6e1b\u3063\u305f\u3002\u5374\u8aac\u3002twitter\u306e\u767e\u56db\u5341\u6587\u5b57\u306b\u82db\u3005\u3068\u3057\u3066\u3001\u4e00\u3064\u306e\u4eee\u8aac\u306b\u4fe1\u6191\u6027\u3092\u5f97\u308b\u3002\u6226\u6642\u4e0b\u306e\u7d19\u306e\u7d71\u5236\u3068\u3001\u4e2d\u5cf6\u6566\u306e\u6587\u7ae0\u306e\u95a2\u4fc2\u6027\u3002\u73fe\u5728\u30a6\u30a7\u30d6\u30ed\u30b0\u306b\u3001\u7e8f\u3081\u3066\u3044\u308b\u6700\u4e2d\u3002\u8fd1\u65e5\u516c\u958b\u4e88\u5b9a\u3002","id":41190190428979200,"from_user_id":200568705,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"164970427","profile_image_url":"http://a0.twimg.com/profile_images/1227176662/9192b021ef85ce9902c28955f86e604b_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:59 +0000","from_user":"syuigetsuIT","id_str":"41190184041197569","metadata":{"result_type":"recent"},"to_user_id":141926331,"text":"@iliad_tga \u30a4\u30ea\u30a2\u30b9\u3055\u3093\u304c\u305d\u306e\u8fba\u7406\u89e3\u306e\u3042\u308b\u3053\u3068\u306f\u5206\u304b\u3063\u3066\u307e\u3059\uff57\u3000\u30cd\u30bf\u30d0\u30ec\u4e91\u3005\u306ftwitter\u306e\u6c7a\u5b9a\u7684\u306a\u6b20\u70b9\u3060\u3068\u601d\u3044\u307e\u3059\u306d\u3047\u3002","id":41190184041197569,"from_user_id":164970427,"to_user":"iliad_tga","geo":null,"iso_language_code":"ja","to_user_id_str":"141926331","source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"94526795","profile_image_url":"http://a0.twimg.com/profile_images/679411954/akb48_in_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:56 +0000","from_user":"akb48_in","id_str":"41190171248431104","metadata":{"result_type":"recent"},"to_user_id":null,"text":"AKB48\u67cf\u6728\u7531\u7d00 \u304a\u75b2\u308c\u69d8\u3002: \n\u3053\u3093\u3070\u3093\u306f(^O^)\uff0f\u266a\n\u3000\n\u3000\n\u3000\n\u4eca\u65e5\u306e\u516c\u6f14\u697d\u3057\u304b\u3063\u305f\u301c\n\u3000\n\u3000\n\u4e45\u3057\u3076\u308a\u3067\u7dca\u5f35\u3057\u305f\u3051\u3069\u3001\u306f\u3058\u3051\u307e\u304f\u3063\u305f\u305c\u3043\uff01\uff01\n\u3000\n\u3000\n\u3000\nMC\u306f\u565b\u307f\u307e\u304f\u308a\u306e\u30c6\u30f3\u30d1\u308a\u307e\u304f... http://bit.ly/ie8bEa akb48 twitter","id":41190171248431104,"from_user_id":94526795,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"222270374","profile_image_url":"http://a3.twimg.com/profile_images/1250946143/P1040062_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:53 +0000","from_user":"chrxpac","id_str":"41190158455943168","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3010\u5b9a\u671f\u3011Twitter\u306f\uff8a\uff9f\uff7f\uff7a\uff9d\u304b\u3089\u3057\u304b\u3067\u304d\u306a\u3044\u306e\u3067\uff98\uff8c\uff9f\u8fd4\u3057\u304c\u9045\u304f\u306a\u308a\u307e\u3059(\u00b4\u30fb\u03c9\u30fb\uff40)\u3054\u4e86\u627f\u4e0b\u3055\u3044!!","id":41190158455943168,"from_user_id":222270374,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>"},{"from_user_id_str":"64009258","profile_image_url":"http://a2.twimg.com/profile_images/1154025023/Mixi___normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:52 +0000","from_user":"Tatsuyuko","id_str":"41190153447944192","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4f01\u696d\u304c\u5c31\u6d3b\u751f\u306bFacebook\u3092\u4f7f\u3063\u3066\u7533\u8acb\u305b\u3088\u3068\u3044\u3044\u3001\u4f01\u696d\u304cFacebook\u3092\u4f7f\u3048\u3068\u4f01\u696d\u304c\u8a00\u3063\u3066\u304d\u305f\u308a\u3059\u308c\u3070\u305d\u308c\u3069\u3053\u308d\u3058\u3083\u306a\u3044\u304b\u3068\u3002\u5c11\u306a\u304f\u3068\u3082\u5c31\u6d3b\u3067Twitter\u306e\u8a00\u52d5\u3084\u30d5\u30a9\u30ed\u30ef\u30fc\u3092\u8abf\u67fb\u3059\u308b\u4f01\u696d\u306f\u304b\u306a\u308a\u591a\u3044\u3067\u3059 RT @Isshee: \u4f01\u696d\u3067\u3082\u540c\u3058\u3067\u3057\u3087 RT","id":41190153447944192,"from_user_id":64009258,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sourceforge.jp/projects/tween/wiki/FrontPage" rel="nofollow">Tween</a>"},{"from_user_id_str":"105145175","profile_image_url":"http://static.twitter.com/images/default_profile_normal.png","created_at":"Fri, 25 Feb 2011 17:37:49 +0000","from_user":"snao813","id_str":"41190141703753728","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @yumisaiki: \u795e\u69d8\u306f\u672c\u5f53\u306b\u4eba\u9593\u3092\u3059\u3070\u3089\u3057\u3044\u30d0\u30e9\u30f3\u30b9\u3067\u914d\u7f6e\u3057\u3066\u304a\u3089\u308c\u308b\u3002\u795d\u5cf6\u307f\u305f\u3044\u306a\u5c0f\u3055\u3044\u3068\u3053\u308d\u306b\u306a\u3093\u3067\u3053\u3093\u306a\u306b\u7acb\u6d3e\u306a\u4eba\u304c\u305f\u304f\u3055\u3093\u3044\u308b\u3093\u3060\u308d\u3046\u3002\u795e\u69d8\u3042\u308a\u304c\u3068\u3046\u3002\u672c\u5f53\u306b\u3042\u308a\u304c\u3068\u3046\u3002\u4eba\u9593\u3063\u3066\u3059\u3070\u3089\u3057\u3044\u3068\u601d\u3048\u305f\u3002twitter\u3082\u3042\u308a\u304c\u3068\u3046\u3002\u3000#kaminoseki","id":41190141703753728,"from_user_id":105145175,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://seesmic.com/seesmic_desktop/sd2" rel="nofollow">Seesmic Desktop</a>"},{"from_user_id_str":"203667204","profile_image_url":"http://a2.twimg.com/profile_images/1254664000/eve_blackcat_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:46 +0000","from_user":"eve_blackcat","id_str":"41190129292943361","metadata":{"result_type":"recent"},"to_user_id":146894340,"text":"@kuroiso02 \u3057\u308a\u3068\u308a\u3068\u304b\uff1f\n\u2026\u3067\u3082Twitter\u3060\u3068\u7d42\u308f\u3089\u306a\u304f\u306a\u308b\u30b1\u30c9\u2026","id":41190129292943361,"from_user_id":203667204,"to_user":"kuroiso02","geo":null,"iso_language_code":"ja","to_user_id_str":"146894340","source":"<a href="http://twipple.jp/" rel="nofollow">\u3064\u3044\u3063\u3077\u308b for iPhone</a>"},{"from_user_id_str":"6528403","profile_image_url":"http://a0.twimg.com/profile_images/1240591244/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:45 +0000","from_user":"sortiee","id_str":"41190125924917248","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30a2\u30cb\u30e1\u5b9f\u6cc1\u306ftwitter\u306e\u764c","id":41190125924917248,"from_user_id":6528403,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sites.google.com/site/peraperaprv/Home" rel="nofollow">P3:PeraPeraPrv</a>"},{"from_user_id_str":"186058304","profile_image_url":"http://a0.twimg.com/profile_images/1250454564/IMG_0210_normal.JPG","created_at":"Fri, 25 Feb 2011 17:37:37 +0000","from_user":"00o8o00","id_str":"41190090386448384","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @fuefukioyasumi: \u3082\u3046\u3044\u3044\u3002\u300c\u671d\u751f\u300d\u306a\u3093\u304b\u3044\u3044\u3002BBC\u3082CNN\u3082\u82f1\u8a9e\u653e\u9001\u3060\u3002\u307f\u3093\u306a\u3001\u30c6\u30ec\u30d3\u3092\u3076\u3061\u3063\u3068\u5207\u3063\u3066Twitter\u3092\u898b\u3088\u3046\u3002\u3053\u3053\u306b\u300c\u751f\u304d\u305f\u60c5\u5831\u300d\u304c\u6d41\u308c\u3066\u3044\u308b\u3002\u300c\u751f\u304d\u305f\u53eb\u3073\u300d\u304c\u3042\u308b\u3002\u3053\u3053\u304b\u3089\u3067\u3082\u6b74\u53f2\u306e\u8ee2\u63db\u70b9\u3092\u611f\u3058\u308b\u4e8b\u304c\u3067\u304d\u308b\u306e\u3060\u3002 @gjmorley #libjp","id":41190090386448384,"from_user_id":186058304,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"49219631","profile_image_url":"http://a2.twimg.com/profile_images/1231873117/__2-colornow__2__normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:33 +0000","from_user":"irisgazer","id_str":"41190073227550720","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3067\u3059\u3088\u306d\u3047 RT @minamitaiheiyou: \u6545\u306b\u30cd\u30bf\u30d0\u30ec\u3092\u3059\u308b\u306e\u3082\u81ea\u7531\u3002\u30cd\u30bf\u3070\u308c\u3057\u305f\u4eba\u3092\u30c7\u30a3\u30b9\u308b\u306e\u3082\u81ea\u7531\u3002\u3042\u3068\u306f\u5404\u3005\u306e\u88c1\u91cf\u3067\u4e57\u308a\u5207\u3063\u3066\u304f\u3060\u3055\u3044\u3088\u3081\u3093\u3069\u304f\u3055\u3044\u306a RT @kihirokiro: Twitter\u3067\u30cd\u30bf\u30d0\u30ec\u4e91\u3005\u3044\u3063\u3066\u3082\u5143\u3005Twitter\u3063\u3066\u300c\u500b\u4eba\u306e\u72ec\u308a\u8a00\u300d\u3060\u308d","id":41190073227550720,"from_user_id":49219631,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sourceforge.jp/projects/tween/wiki/FrontPage" rel="nofollow">Tween</a>"},{"from_user_id_str":"98560114","profile_image_url":"http://a0.twimg.com/profile_images/1252332545/IMGP8170_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:32 +0000","from_user":"qess0093","id_str":"41190070706905088","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30b7\u30e5\u30fc\u30c6\u30a3\u304f\u305d\u3046\u305c\u3048\uff57 RT @syu_thi_bot: \u3044\u3064\u307e\u3067Twitter\u3084\u3063\u3066\u308b\u3093\u3060\u3044\uff1f\u3044\u3044\u52a0\u6e1b\u73fe\u5b9f\u306b\u623b\u308a\u306a\u3088\u3002\u3053\u3053\u306f\u30ad\u30df\u305f\u3061\u4e09\u6b21\u5143\u306e\u4eba\u9593\u304c\u3044\u308b\u3079\u304d\u5834\u6240\u3058\u3083\u306a\u3044\u3093\u3060\u3088\u3002\u305d\u3093\u306a\u306e\u57fa\u672c\u3060\u308d\uff01\uff01","id":41190070706905088,"from_user_id":98560114,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://sourceforge.jp/projects/tween/wiki/FrontPage" rel="nofollow">Tween</a>"},{"from_user_id_str":"197459334","profile_image_url":"http://a3.twimg.com/profile_images/1210698414/shiratorishoko_normal.png","created_at":"Fri, 25 Feb 2011 17:37:31 +0000","from_user":"SyokoShiratori","id_str":"41190064243478528","metadata":{"result_type":"recent"},"to_user_id":null,"text":"+0.50kg \u540c\u3058\u304f\u30c0\u30a4\u30a8\u30c3\u30c8\u4e2d\u3067\u3059\u3002\u3088\u304f\u3053\u306e\u30b5\u30a4\u30c8\u3067\u4f53\u91cd\u5831\u544a\u3057\u3066\u307e\u3059\u266a http://bit.ly/fhN2fM RT @msophiah \u3046\u3046\u3046\u30fb\u30fb\u30fb\u304a\u8179\u3059\u3044\u305f\u301c\u30fb\u30fb\u30fb\u6211\u6162\u3001\u6211\u6162\u3001\u6211\u6162\u3002\u30c0\u30a4\u30a8\u30c3\u30c8\u3001\u30c0\u30a4\u30a8\u30c3\u30c8\u3001\u30c0\u30a4\u30a8\u30c3\u30c8\u3002","id":41190064243478528,"from_user_id":197459334,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://mob-mc.com" rel="nofollow">\uff08\u4eee\u79f0\uff09\u30c4\u30a4\u30af\u30ea\u30c3\u30af twiclick</a>"},{"from_user_id_str":"180410237","profile_image_url":"http://a3.twimg.com/profile_images/1254473979/icon_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:30 +0000","from_user":"ka_ph","id_str":"41190062184079360","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3010\u5b9a\u671fpost\u3011\u30d5\u30a7\u30eb\u30c7\u30a3\u30ca\u30f3\u30c8bot( http://twitter.com/ferdinand_bot )\u4f5c\u308a\u307e\u3057\u305f\u3002\u304a\u5b50\u69d8\u306e\u540d\u524d\u304a\u501f\u308a\u3055\u305b\u3066\u304f\u308c\u308b\u65b9\u3044\u307e\u3057\u305f\u3089@ka_ph\u307e\u3067\u304a\u9858\u3044\u3057\u307e\u3059\u3002","id":41190062184079360,"from_user_id":180410237,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>"},{"from_user_id_str":"52283906","profile_image_url":"http://a3.twimg.com/profile_images/387644016/10100654519_s_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:26 +0000","from_user":"rolling_bean","id_str":"41190043313913856","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3081\u307e\u3044\u304c\u3057\u307e\u3059\u306d\u301cRT @yurikalin:\u30b3\u30a4\u30c4\u30e9\u5168\u54e1\u3044\u306a\u304f\u306a\u3063\u305f\u3089\u3001\u660e\u308b\u304f\u306a\u308b\u3060\u308d\u3046\u306a\u3041\uff5e\u266a\uff1e\u65e5\u672c\u306e\u30d3\u30b8\u30e7\u30f3 RT roll \u65e5\u7d4c\uff06CSIS\u30b7\u30f3\u30dd\u30b8\u30a6\u30e0\u300c\u5b89\u4fdd\u6539\u5b9a50\u5468\u5e74\u3001\u3069\u3046\u306a\u308b\u65e5\u7c73\u95a2\u4fc2\u300d http://bit.ly/dES8PY\u3000http://bit.ly/ihg0GT","id":41190043313913856,"from_user_id":52283906,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://tabtter.jp" rel="nofollow">\u30bf\u30d6\u30c3\u30bf\u30fc</a>"},{"from_user_id_str":"351896","profile_image_url":"http://a3.twimg.com/profile_images/1179865336/icon12911887173020_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:26 +0000","from_user":"cicada","id_str":"41190043292925952","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4e2d\u5b66\u53d7\u9a13\u7a0b\u5ea6\u306e\u7b97\u6570\u306e\u554f\u984c\u3092\u51fa\u3059BOT http://twitter.com/arithmetic_bot \u6c17\u306b\u306f\u306a\u308b\u304c\u3001\u3061\u3083\u3093\u3068\u898b\u308b\u65e5\u304c\u6765\u308b\u3060\u308d\u3046\u304b\u30fb\u30fb\u3000#tearai\uff1a\u30ed\u30b3\u30e9\u30dc\u5bae\u5d0e\u770c http://locolabo.com/mz/ #mzlf","id":41190043292925952,"from_user_id":351896,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://locolabo.com/mz/" rel="nofollow">\u30ed\u30b3\u30e9\u30dc\u5bae\u5d0e\u770c</a>"},{"from_user_id_str":"744554","profile_image_url":"http://a1.twimg.com/profile_images/1088753125/11868894_normal.gif","created_at":"Fri, 25 Feb 2011 17:37:20 +0000","from_user":"Febreze","id_str":"41190019020505088","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30cd\u30bf\u30d0\u30ec\u3042\u307e\u308a\u6c17\u306b\u3057\u306a\u3044\u30bf\u30a4\u30d7\u3060\u3051\u3069\u306a\u3093\u304b\u3053\u3046Twitter\u958b\u304f\u3060\u3051\u3067\u30ac\u30f3\u30ac\u30f3\u30cd\u30bf\u30d0\u30ec\u5165\u3063\u3066\u304f\u308b\u306e\u306f\u306a\u3093\u3068\u3082\u8a00\u3048\u306a\u3044\u306a\u3002","id":41190019020505088,"from_user_id":744554,"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":"203371794","profile_image_url":"http://a1.twimg.com/profile_images/1226537594/___normal.png","created_at":"Fri, 25 Feb 2011 17:37:16 +0000","from_user":"himeko24","id_str":"41190004139114496","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6b21\u3044\u3063\u3066\u307f\u3088\u30fc\u3000\u306f\u3044\u3053\u308c\u3000 \u6fc0\u5b89\u26052010\u5e74\u590f\u65b0\u30c7\u30b6\u30a4\u30f3\u2605\u30bb\u30af\u30b7\u30fc\u306a\u9023\u4f53\u5f0f\u7121\u5730\u6c34\u7740 \u80f8\u30d1\u30c3\u30c9\u4ed8\u304dQ122 http://bit.ly/h72C4i","id":41190004139114496,"from_user_id":203371794,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.google.co.jp" rel="nofollow">himeko24</a>"},{"from_user_id_str":"119988932","profile_image_url":"http://a3.twimg.com/profile_images/1214344633/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:16 +0000","from_user":"7na_love_6sa","id_str":"41190002000007169","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30d6\u30ed\u30b0\u66f4\u65b0\u3057\u307e\u3057\u305f\uff01Twitter\uff06mixi\u304b\u3089\u3082\u30b3\u30e1\u30f3\u30c8\u5b9c\u3057\u304f\u306d\u266a\n\u300c\u30cd\u30a4\u30eb\u30c1\u30a7\u30f3\u30b8\u266a\u300d http://amba.to/hy0Do2","id":41190002000007169,"from_user_id":119988932,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"217408835","profile_image_url":"http://a1.twimg.com/profile_images/1215428655/____4.0157_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:12 +0000","from_user":"nikubenki1123","id_str":"41189985424125952","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @x68k: \u57fa\u672c\u7684\u306bTwitter\u4e0a\u3067\u306f"\u597d\u304d\u306b\u3084\u308c\u3070\u3044\u3044"\u3060\u3051\u3069\u3001\u540d\u524d\u3082\u30a2\u30a4\u30b3\u30f3\u3082\u30a2\u30f3\u30bf\u3058\u3083\u306a\u3044\u305f\u304f\u3055\u3093\u306e\u4eba\u305f\u3061\u306e\u9b42\u304c\u3053\u3082\u3063\u305f\u3082\u306e\u306a\u306e\u3060\u304b\u3089\u3001\u305d\u308c\u3060\u3051\u306f"\u80cc\u8ca0\u3048"\u3068\u601d\u3046\uff1e\u30ad\u30e3\u30e9\u30af\u30bf\u30fc\u30a2\u30ab\u30a6\u30f3\u30c8","id":41189985424125952,"from_user_id":217408835,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://tweetlogix.com" rel="nofollow">Tweetlogix</a>"},{"from_user_id_str":"139137996","profile_image_url":"http://a0.twimg.com/profile_images/1087408006/cut_work_18_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:12 +0000","from_user":"fujiokayouko","id_str":"41189984354566144","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u591c\u4e2d\u306bTwitter\u3092\u306a\u3093\u3068\u306a\u304f\u8997\u3044\u305f\u3089\u3082\u306e\u3059\u3054\u3044\u307e\u3069\u30de\u30aeTL\u3067","id":41189984354566144,"from_user_id":139137996,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://mobile.twitter.com" rel="nofollow">Mobile Web</a>"},{"from_user_id_str":"61221002","profile_image_url":"http://a3.twimg.com/profile_images/554916301/_1259757374_61_normal.png","created_at":"Fri, 25 Feb 2011 17:37:08 +0000","from_user":"hiromk63","id_str":"41189970613903360","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @kenji_kohashi \u7121\u4e8b\u6620\u753b\u88fd\u4f5c\u306e\u5831\u544a\u306f\u3067\u304d\u305f\u3051\u3069\u4eca\u3060\u7de8\u96c6\u306f\u7d9a\u3044\u3066\u307e\u3059w \u305d\u3093\u306a\u3068\u3053\u3067 \u6620\u753b\u300cDON'T STOP!\u300d\u306eTwitter \u30a2\u30ab\u30a6\u30f3\u30c8 @DONTSTOPMOVIE \u3082\u958b\u59cb\u3001\u3082\u3057\u826f\u304b\u3063\u305f\u3089\u30d5\u30a9\u30ed\u30fc\u3057\u3066\u304f\u3060\u3055\u3044\uff01\u50d5\u3082\u542b\u3081\u6620\u753b\u88fd\u4f5c\u95a2\u4fc2\u8005\u304c\u6c17\u9577\u306b\u3064\u3076\u3084\u304d\u307e\u3059","id":41189970613903360,"from_user_id":61221002,"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":"147393812","profile_image_url":"http://a1.twimg.com/profile_images/1114001122/hana_10_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:07 +0000","from_user":"tubasa_uki","id_str":"41189965924667392","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\uff10\uff10\uff17\u3082\u3073\u3063\u304f\u308a\u3000\u5927\u56fd\u306e\u5927\u7d71\u9818\u9078\u304b\u3089\u3000\u5cf6\u56fd\u306e\u5730\u65b9\u9078\u306e\u9078\u6319\u307e\u3067\u306b\u3082\u3000\u6697\u8e8d\u3057\u3066\u3044\u308b\uff3e\uff3e\u3000\u3053\u306eTwitter \u30b9\u30ad\u30e3\u30f3\u30c0\u30eb\u3084\u60aa\u8cea\u306a\u4e8b\u4ef6\u306b\u3082\u7d61\u3080\u304c\u3000Twitter\u304b\u3089\u767a\u4fe1\u3055\u308c\u305f\u3000\u5e73\u548c\u3078\u306e\u8ca2\u732e\u306f\u3000\u307e\u3055\u306b\u30ce\u30fc\u3079\u30eb\u5e73\u548c\u8cde\u3082\u306e http://bit.ly/esjWDG #dotubo_ss","id":41189965924667392,"from_user_id":147393812,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>"},{"from_user_id_str":"96081746","profile_image_url":"http://a0.twimg.com/profile_images/1244505419/illust832_normal.png","created_at":"Fri, 25 Feb 2011 17:37:07 +0000","from_user":"kazukt","id_str":"41189963131387904","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3046\u308b\u304a\u307c\u7d75\u3001\u4ed6\u306e\u4eba\u306e\u3082\u898b\u3066\u3044\u305f\u3089\u3084\u305f\u3089\u30de\u30f3\u30ac\u306e\u30ad\u30e3\u30e9\u30af\u30bf\u30fc\u3067\u3080\u3061\u3083\u304f\u3061\u3083\u4e0a\u624b\u3044\u4eba\u304c\uff01\u2026\u3068\u3001\u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\u898b\u305f\u3089\u3001\u306a\u3093\u3068\u3054\u672c\u4eba\u304c\u66f8\u3044\u3066\u3044\u3089\u3063\u3057\u3083\u3063\u305f\u3002Twitter\u3063\u3066\u30b9\u30b4\u30a4\u308f\u3002","id":41189963131387904,"from_user_id":96081746,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://janetter.net/" rel="nofollow">Janetter</a>"},{"from_user_id_str":"86306230","profile_image_url":"http://a1.twimg.com/profile_images/593004766/j2j_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:03 +0000","from_user":"excite_j2j","id_str":"41189949927596032","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u79c1\u306f\u3001\u65e9\u7a32\u7530\u5927\u5b66\u30aa\u30fc\u30d7\u30f3\u30ab\u30ec\u30c3\u30b8\u306e\u5b66\u751f\u306e\u8003\u3048\u3066\u3044\u308b\u3001\u5352\u696d\u751fSoudai /\u65e9\u7a32\u7530\u30ab\u30fc\u30c9\u4f1a\u54e1/ Soudai\u5b66\u751f\u89aa/\u3001\u8ab0\u304b\u304c\u30aa\u30fc\u30d7\u30f3\u30ab\u30ec\u30c3\u30b8\u65e9\u7a32\u7530\u5927\u5b662000\u5186\u306e\u5165\u5834\u6599\u306e\u30e1\u30f3\u30d0\u30fc\u3092\u7d39\u4ecb\u3057\u3066\u304f\u308c\u305f\u65b9\u304c\u305a\u3063\u3068\u5b89\u4e0a\u304c\u308a\u3060\u3002 (\u5143\u767a\u8a00 http://bit.ly/esxiwT )","id":41189949927596032,"from_user_id":86306230,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://d.hatena.ne.jp/fn7" rel="nofollow">\u65e5\u672c\u8a9e\u65e5\u672c\u8a9e\u7ffb\u8a33\u30b8\u30a7\u30cd\u30ec\u30fc\u30bf</a>"},{"from_user_id_str":"120927161","profile_image_url":"http://a0.twimg.com/profile_images/1230006483/20110131_13022_26776_normal.jpg","created_at":"Fri, 25 Feb 2011 17:37:00 +0000","from_user":"FRISKFOSSILFANG","id_str":"41189933855158272","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @syu_thi_bot: \u3044\u3064\u307e\u3067Twitter\u3084\u3063\u3066\u308b\u3093\u3060\u3044\uff1f\u3044\u3044\u52a0\u6e1b\u73fe\u5b9f\u306b\u623b\u308a\u306a\u3088\u3002\u3053\u3053\u306f\u30ad\u30df\u305f\u3061\u4e09\u6b21\u5143\u306e\u4eba\u9593\u304c\u3044\u308b\u3079\u304d\u5834\u6240\u3058\u3083\u306a\u3044\u3093\u3060\u3088\u3002\u305d\u3093\u306a\u306e\u57fa\u672c\u3060\u308d\uff01\uff01","id":41189933855158272,"from_user_id":120927161,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>"},{"from_user_id_str":"228973151","profile_image_url":"http://a1.twimg.com/sticky/default_profile_images/default_profile_0_normal.png","created_at":"Fri, 25 Feb 2011 17:36:59 +0000","from_user":"daisuke1589","id_str":"41189931887890432","metadata":{"result_type":"recent"},"to_user_id":null,"text":"twitter\u3063\u3066\u52dd\u624b\u306b\u30d5\u30a9\u30ed\u30fc\u3057\u3066\u3082\u3044\u3044\u3093\u3060\u3063\u3051\uff1f","id":41189931887890432,"from_user_id":228973151,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"54314110","profile_image_url":"http://a2.twimg.com/profile_images/1193541240/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:57 +0000","from_user":"Alohazuki","id_str":"41189922668953600","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Twitter\u306e\u5e83\u5cf6\u5f01\u3082\u3042\u3063\u305f\u3093\u3060\u306d\u3002","id":41189922668953600,"from_user_id":54314110,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.flight.co.jp/iPhone/TweetMe/" rel="nofollow">TweetMe for iPhone</a>"},{"from_user_id_str":"72594681","profile_image_url":"http://a3.twimg.com/profile_images/1227240916/____normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:56 +0000","from_user":"uri4ichi","id_str":"41189916922744832","metadata":{"result_type":"recent"},"to_user_id":226852303,"text":"@7_fuka Twitter\u304b\u3076\u308c\u306f\u3001\u3059\u3050\u306bD\u306b\u8d70\u308b\u306e\u3067\u3002\u306a\u3093\u3060\u304b\u5fae\u7b11\u307e\u3057\u3044\u306e\u3067\u3059( \u2579\u25e1\u2579)","id":41189916922744832,"from_user_id":72594681,"to_user":"7_fuka","geo":null,"iso_language_code":"ja","to_user_id_str":"226852303","source":"<a href="http://sites.google.com/site/yorufukurou/" rel="nofollow">YoruFukurou</a>"},{"from_user_id_str":"168393854","profile_image_url":"http://a3.twimg.com/profile_images/1253554518/GuNp3xVS_normal","created_at":"Fri, 25 Feb 2011 17:36:55 +0000","from_user":"makonyanhime","id_str":"41189913701515264","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6589\u85e4\u3055\u3093\u3082\u30c0\u30e1\u3060...\u4eca\u591c\u306fTwitter\u5909\u3060\u306a\u3041(;_;)","id":41189913701515264,"from_user_id":168393854,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://mobile.twitter.com" rel="nofollow">Twitter for Android</a>"},{"from_user_id_str":"122636787","profile_image_url":"http://a2.twimg.com/profile_images/1189607563/DSC01987_normal.JPG","created_at":"Fri, 25 Feb 2011 17:36:54 +0000","from_user":"enpy1217","id_str":"41189908500594688","metadata":{"result_type":"recent"},"to_user_id":null,"text":"twitter\u4e45\u3057\u3076\u308a\u306b\u958b\u3044\u305f\u3002\u3068\u3066\u3082\u591a\u5fd9\u3060\u3063\u305f\u3002\u75b2\u308c\u305f\u3002\u304a\u98a8\u5442\u306b\u3082\u5165\u308c\u306a\u304b\u3063\u305f\u3002\u30ad\u30bf\u30cd\u2026","id":41189908500594688,"from_user_id":122636787,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.flight.co.jp/iPhone/TweetMe/" rel="nofollow">TweetMe for iPhone</a>"},{"from_user_id_str":"81663694","profile_image_url":"http://a3.twimg.com/profile_images/1177576126/__normal.png","created_at":"Fri, 25 Feb 2011 17:36:51 +0000","from_user":"progmiya","id_str":"41189895494049792","metadata":{"result_type":"recent"},"to_user_id":94050844,"text":"@hirasai_skyhigh \u6674\u308c\u541b\u3002\u30cd\u30bf\u30d0\u30ec\u306f\u898b\u305f\u304f\u306a\u3044\u3051\u3069\u30012ch\u3082twitter\u3082\u3084\u308a\u305f\u3044\u306e\u304c\u4eba\u3068\u8a00\u3046\u3082\u306e\u3088","id":41189895494049792,"from_user_id":81663694,"to_user":"hirasai_skyhigh","geo":null,"iso_language_code":"ja","to_user_id_str":"94050844","source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"159237469","profile_image_url":"http://a3.twimg.com/profile_images/1140433484/______2_normal.png","created_at":"Fri, 25 Feb 2011 17:36:50 +0000","from_user":"hikari_juku","id_str":"41189892096532480","metadata":{"result_type":"recent"},"to_user_id":135634241,"text":"@sssukimasuky \n\u4f55\u304b\u3042\u3063\u305f\u98a8\u3067\u3059\u306d\uff08\u7b11\uff09\u3000\u78ba\u304b\u306bTwitter\u306f\u6c17\u8efd\u3067\u3059\u3057\u306d\u3002\u30e1\u30fc\u30eb\u306b\u306a\u308b\u3068\u30d5\u30c3\u30c8\u30ef\u30fc\u30af\u304c\u91cd\u304f\u306a\u308b\u5834\u5408\u3082\u3042\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u306d\u3002\u305d\u3046\u8003\u3048\u308b\u3068\u3059\u3054\u3044\u6642\u4ee3\u3060\u3002","id":41189892096532480,"from_user_id":159237469,"to_user":"sssukimasuky","geo":null,"iso_language_code":"ja","to_user_id_str":"135634241","source":"<a href="http://www.hootsuite.com" rel="nofollow">HootSuite</a>"},{"from_user_id_str":"141915990","profile_image_url":"http://a0.twimg.com/profile_images/1248969898/icon679566266564378764images_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:48 +0000","from_user":"adashino_","id_str":"41189886878949376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @fuefukioyasumi: \u3082\u3046\u3044\u3044\u3002\u300c\u671d\u751f\u300d\u306a\u3093\u304b\u3044\u3044\u3002BBC\u3082CNN\u3082\u82f1\u8a9e\u653e\u9001\u3060\u3002\u307f\u3093\u306a\u3001\u30c6\u30ec\u30d3\u3092\u3076\u3061\u3063\u3068\u5207\u3063\u3066Twitter\u3092\u898b\u3088\u3046\u3002\u3053\u3053\u306b\u300c\u751f\u304d\u305f\u60c5\u5831\u300d\u304c\u6d41\u308c\u3066\u3044\u308b\u3002\u300c\u751f\u304d\u305f\u53eb\u3073\u300d\u304c\u3042\u308b\u3002\u3053\u3053\u304b\u3089\u3067\u3082\u6b74\u53f2\u306e\u8ee2\u63db\u70b9\u3092\u611f\u3058\u308b\u4e8b\u304c\u3067\u304d\u308b\u306e\u3060\u3002 @gjmorley #libjp","id":41189886878949376,"from_user_id":141915990,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"111308629","profile_image_url":"http://a1.twimg.com/profile_images/1137421845/mmooton_normal.png","created_at":"Fri, 25 Feb 2011 17:36:46 +0000","from_user":"mmooton","id_str":"41189877940748288","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @minponjp: \u3010\u3064\u3076\u3084\u304f\u3060\u3051\u306710000\u5186\u5546\u54c1\u5238GET\u3011<<visa\u30ae\u30d5\u30c8\u30ab\u30fc\u30c910000\u5186\u5206\u3092\u6bce\u6708\u62bd\u9078\u3067\u30d7\u30ec\u30bc\u30f3\u30c8>> \u21d2\u8a73\u3057\u304f\u306f\u4e0b\u306e\uff35\uff32\uff2c\u3088\u308a\u2193\u2193\u2193\u2193\u2193 http://minpon.jp/user_data/twitter_campaign.php","id":41189877940748288,"from_user_id":111308629,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>"},{"from_user_id_str":"140945098","profile_image_url":"http://a0.twimg.com/profile_images/1198948281/b7664c71-87bc-4187-9d46-a61ab8d41b96_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:46 +0000","from_user":"waruimayuko","id_str":"41189877122867200","metadata":{"result_type":"recent"},"to_user_id":113371008,"text":"@toumeisyoujyo \u3042\u3053\u3061\u3083\u3093Twitter\u3084\u3063\u3066\u305f\u306e\u306d\u3002\u307e\u3060\u304a\u5e2d\u3042\u308b\u305d\u3046\u306a\u306e\u3067\u662f\u975e\uff01","id":41189877122867200,"from_user_id":140945098,"to_user":"toumeisyoujyo","geo":null,"iso_language_code":"ja","to_user_id_str":"113371008","source":"<a href="http://twimi.jp/?r=via" rel="nofollow">twimi\u2606new</a>"},{"from_user_id_str":"167512527","profile_image_url":"http://a1.twimg.com/profile_images/1172286365/newspaper_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:45 +0000","from_user":"KoranKaget","id_str":"41189871775252480","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://bit.ly/93Eeud RT @motocentrism \u30d6\u30ed\u30b0\u8a18\u4e8b\u66f8\u304d\u307e\u3057\u305f\u30fc\uff1a MotoGP\u3000\u30d6\u30c3\u30af\u30e1\u30fc\u30ab\u30fc\u306b\u898b\u308b\u5404\u30e9\u30a4\u30c0\u30fc\u306e\u4e0b\u99ac\u8a55 - http://goo.gl/xVe6... http://bit.ly/hDYxyx @motogpudpate","id":41189871775252480,"from_user_id":167512527,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitterfeed.com" rel="nofollow">twitterfeed</a>"},{"from_user_id_str":"160251772","profile_image_url":"http://a3.twimg.com/profile_images/1150692471/_____normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:45 +0000","from_user":"keikochaki","id_str":"41189870781075456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u300c\u305a\u3063\u3068twitter\u3084\u3063\u3066\u308b\u3088\u306d\u300d\u3068\u6012\u3089\u308c\u3066\u3057\u307e\u3063\u305f(\u82e6\u7b11)","id":41189870781075456,"from_user_id":160251772,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twtr.jp" rel="nofollow">Keitai Web</a>"},{"from_user_id_str":"211565766","profile_image_url":"http://a2.twimg.com/sticky/default_profile_images/default_profile_5_normal.png","created_at":"Fri, 25 Feb 2011 17:36:42 +0000","from_user":"sayap1yo","id_str":"41189858236043264","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u304a\u98df\u4e8b\u4f1a\u884c\u304d\u305f\u304b\u3063\u305f\u3051\u3069\n\u53cb\u9054\u3068\u904a\u3093\u3067\u307e\u3093\u305f\ue056\ue326\n\nTwitter\u898b\u3066\u307e\u3057\u305f\u3051\u3069\n\u3064\u3076\u3084\u304f\u30bf\u30a4\u30df\u30f3\u30b0\n\u5931\u3063\u3066\u305f\u3060\u3051\u3067\u3059( \u00b4 \u25bd ` )\uff89\u7b11","id":41189858236043264,"from_user_id":211565766,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.nibirutech.com" rel="nofollow">TwitBird</a>"},{"from_user_id_str":"19603191","profile_image_url":"http://a1.twimg.com/profile_images/1254077264/116_normal.gif","created_at":"Fri, 25 Feb 2011 17:36:40 +0000","from_user":"Purple_Flash","id_str":"41189851873157120","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @syu_thi_bot: \u3044\u3064\u307e\u3067Twitter\u3084\u3063\u3066\u308b\u3093\u3060\u3044\uff1f\u3044\u3044\u52a0\u6e1b\u73fe\u5b9f\u306b\u623b\u308a\u306a\u3088\u3002\u3053\u3053\u306f\u30ad\u30df\u305f\u3061\u4e09\u6b21\u5143\u306e\u4eba\u9593\u304c\u3044\u308b\u3079\u304d\u5834\u6240\u3058\u3083\u306a\u3044\u3093\u3060\u3088\u3002\u305d\u3093\u306a\u306e\u57fa\u672c\u3060\u308d\uff01\uff01","id":41189851873157120,"from_user_id":19603191,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>"},{"from_user_id_str":"215930291","profile_image_url":"http://a0.twimg.com/profile_images/1247906106/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:30 +0000","from_user":"minori_millie","id_str":"41189810055938048","metadata":{"result_type":"recent"},"to_user_id":212972774,"text":"@c_c_chika \u7b11\u3063\u3066\u305d\u3046\u3060\u306a\u3063\u3066\u601d\u3063\u3066\u305f(o^^o)\u30c1\u30ab\u306e\u7b11\u3044\u58f0\u304c\u805e\u3053\u3048\u3066\u304d\u305f\u3082\u3093\u3002mail\u306bTwitter\u3067\u5927\u5fd9\u3057\u3084\u3002","id":41189810055938048,"from_user_id":215930291,"to_user":"c_c_chika","geo":null,"iso_language_code":"ja","to_user_id_str":"212972774","source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"},{"from_user_id_str":"197459334","profile_image_url":"http://a3.twimg.com/profile_images/1210698414/shiratorishoko_normal.png","created_at":"Fri, 25 Feb 2011 17:36:30 +0000","from_user":"SyokoShiratori","id_str":"41189809586311168","metadata":{"result_type":"recent"},"to_user_id":null,"text":"+0.90kg \u30c0\u30a4\u30a8\u30c3\u30c8\u5fdc\u63f4\u3057\u3066\u307e\u3059\u3002(*^^*)\u30c0\u30a4\u30a8\u30c3\u30c8\u4f53\u91cd\u5831\u544a\u306e\u3064\u3076\u3084\u304d\u3067\u3059\u3002 http://bit.ly/fhN2fM RT @hayayumi \u3053\u3093\u306a\u6642\u9593\u306b\u3084\u304d\u306b\u304f\u30fc\u266b\u30c0\u30a4\u30a8\u30c3\u30c8\u671f\u9593\u306a\u306e\u306b\u306d....","id":41189809586311168,"from_user_id":197459334,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://mob-mc.com" rel="nofollow">\uff08\u4eee\u79f0\uff09\u30c4\u30a4\u30af\u30ea\u30c3\u30af twiclick</a>"},{"from_user_id_str":"12337665","profile_image_url":"http://a0.twimg.com/profile_images/1146194926/pixiv-icon_normal.png","created_at":"Fri, 25 Feb 2011 17:36:27 +0000","from_user":"t_a_k_i","id_str":"41189797364121600","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Google\u30ea\u30fc\u30c0\u30fc\u3067\u30b5\u30a4\u30c8\u306e\u66f4\u65b0\u30c1\u30a7\u30c3\u30af\u3059\u308b\u3088\u308a\u3001Twitter\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u30d5\u30a9\u30ed\u30fc\u3057\u3066\u66f4\u65b0\u3092\u77e5\u308b\u307b\u3046\u304c\u4fbf\u5229\u3060\u306a\u3053\u308c","id":41189797364121600,"from_user_id":12337665,"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":"104862453","profile_image_url":"http://a3.twimg.com/profile_images/1248609864/Image014_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:25 +0000","from_user":"yuz_ume","id_str":"41189787943714816","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @fuefukioyasumi: \u3082\u3046\u3044\u3044\u3002\u300c\u671d\u751f\u300d\u306a\u3093\u304b\u3044\u3044\u3002BBC\u3082CNN\u3082\u82f1\u8a9e\u653e\u9001\u3060\u3002\u307f\u3093\u306a\u3001\u30c6\u30ec\u30d3\u3092\u3076\u3061\u3063\u3068\u5207\u3063\u3066Twitter\u3092\u898b\u3088\u3046\u3002\u3053\u3053\u306b\u300c\u751f\u304d\u305f\u60c5\u5831\u300d\u304c\u6d41\u308c\u3066\u3044\u308b\u3002\u300c\u751f\u304d\u305f\u53eb\u3073\u300d\u304c\u3042\u308b\u3002\u3053\u3053\u304b\u3089\u3067\u3082\u6b74\u53f2\u306e\u8ee2\u63db\u70b9\u3092\u611f\u3058\u308b\u4e8b\u304c\u3067\u304d\u308b\u306e\u3060\u3002 @gjmorley #libjp","id":41189787943714816,"from_user_id":104862453,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"213846746","profile_image_url":"http://a1.twimg.com/profile_images/1242263342/haruhi1_normal.png","created_at":"Fri, 25 Feb 2011 17:36:23 +0000","from_user":"sloth888jpgame","id_str":"41189778409922560","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u643a\u5e2f\u96fb\u8a71\u7528\u306eTwitter\u3092\u5229\u7528\u3057\u305f\u30b2\u30fc\u30e0\u3092\u77e5\u3063\u3066\u3044\u308b\u4eba\u306f\u3001\u7d39\u4ecb\u3057\u3066\u304f\u3060\u3055\u3044\u3002 #TwitterGame","id":41189778409922560,"from_user_id":213846746,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>"},{"from_user_id_str":"17484724","profile_image_url":"http://a2.twimg.com/profile_images/1138677235/iconue_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:22 +0000","from_user":"tsutcho","id_str":"41189777831231490","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30a2\u30aa\u30b7\u30de\u3055\u3093twitter\u306b\u7acb\u3064\u30fb\u30fb\u30fb\u3060\u3068\u30fb\u30fb\u30fb\uff1f\uff12\u756a\u76ee\u306e\u30d5\u30a9\u30ed\u30ef\u30fc\u306e\u5ea7\u3092\u3044\u305f\u3060\u3044\u3066\u304a\u3053\u3046","id":41189777831231490,"from_user_id":17484724,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"220041064","profile_image_url":"http://a1.twimg.com/sticky/default_profile_images/default_profile_0_normal.png","created_at":"Fri, 25 Feb 2011 17:36:21 +0000","from_user":"sloth888jp_bot5","id_str":"41189772521254914","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6642\u3005\u3001TwiAll\uff08\u30c4\u30a4\u30aa\u30fc\u30eb\uff09\u3067Twitter\u306e\u81ea\u52d5\u30d5\u30a9\u30ed\u30fc\u30fb\u30d5\u30a9\u30ed\u30fc\u8fd4\u3057\u3092\u3057\u3066\u3044\u307e\u3059\u3002","id":41189772521254914,"from_user_id":220041064,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twittbot.net/" rel="nofollow">twittbot.net</a>"},{"from_user_id_str":"177693537","profile_image_url":"http://a0.twimg.com/profile_images/1240130924/20110207213206_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:21 +0000","from_user":"Na_Okinawa","id_str":"41189769912397824","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @ebizo66: \u30ea\u30d3\u30a2\u30fb\u30c8\u30ea\u30dd\u30ea\u306eTw\uff1a\u6551\u6025\u8eca\u304c\u6765\u305f\u304c\u3001\u8ca0\u50b7\u8005\u3092\u8eca\u5185\u3067\u6bba\u5bb3\u3057\u3066\u3044\u305f\u3001\u3068\u3002\uff08\u6ec5\u8336\u82e6\u8336\u3060\uff01\uff09http://ow.ly/43pQ2 #libjp","id":41189769912397824,"from_user_id":177693537,"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":"147006592","profile_image_url":"http://a2.twimg.com/profile_images/1251306448/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:19 +0000","from_user":"takasu_rika","id_str":"41189763532865536","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @kihirokiro: Twitter\u3067\u30cd\u30bf\u30d0\u30ec\u4e91\u3005\u3044\u3063\u3066\u3082\u5143\u3005Twitter\u3063\u3066\u300c\u500b\u4eba\u306e\u72ec\u308a\u8a00\u300d\u3060\u308d","id":41189763532865536,"from_user_id":147006592,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>"},{"from_user_id_str":"100239985","profile_image_url":"http://a1.twimg.com/profile_images/733461294/CIMG0207_normal.JPG","created_at":"Fri, 25 Feb 2011 17:36:19 +0000","from_user":"strangebarjun","id_str":"41189762182152192","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Twitter\u3092\u59cb\u3081\u3066\u3001\u305d\u308d\u305d\u308d\u4e00\u5e74\u306b\u306a\u308a\u307e\u3059\u3002\u632f\u308a\u8fd4\u308b\u3068\u3001\u307c\u304f\u306e\u4eba\u9593\u6027\u3092\u305d\u3063\u304f\u308a\u53cd\u6620\u3059\u308b\u304c\u5982\u304f\u3001\u534a\u7aef\u3067\u3059\u306d\u3002\u60c5\u5831\u53ce\u96c6\u30c4\u30fc\u30eb\u3001\u60c5\u5831\u767a\u4fe1\u30c4\u30fc\u30eb\u3001\u30b3\u30df\u30e5\u30cb\u30b1\u30fc\u30b7\u30e7\u30f3\u30c4\u30fc\u30eb\u3001\u3069\u308c\u3082\u6a5f\u80fd\u3057\u5207\u308c\u3066\u3044\u306a\u3044\u306a\u3042\u3001\u3068\u3002\u305d\u3057\u3066\u3042\u308b\u306e\u306f\u300c\u3069\u3053\u304b\u3089\u3082\u76f8\u624b\u306b\u3055\u308c\u3066\u3044\u306a\u3044\u300d\u3068\u3044\u3046\u3001\u65e2\u77e5\u306e\u73fe\u5b9f\u3067\u3059\u3002","id":41189762182152192,"from_user_id":100239985,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>"},{"from_user_id_str":"126390384","profile_image_url":"http://a2.twimg.com/profile_images/1176065038/nemunemu_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:18 +0000","from_user":"gesukapper","id_str":"41189757476286464","metadata":{"result_type":"recent"},"to_user_id":80935865,"text":"@tatsugorou \u306a\u3093\u304b\u4e16\u306e\u4e2d\u306b\u306f\u611a\u75f4\u3082\u4e0b\u30cd\u30bf\u3082\u8a00\u3044\u653e\u984c\u306etwitter\u3068\u3044\u3046\u3082\u306e\u304c\u3042\u308b\u305d\u3046\u3067\u3059\u3002","id":41189757476286464,"from_user_id":126390384,"to_user":"tatsugorou","geo":null,"iso_language_code":"ja","to_user_id_str":"80935865","source":"<a href="http://janetter.net/" rel="nofollow">Janetter</a>"},{"from_user_id_str":"196059029","profile_image_url":"http://a1.twimg.com/profile_images/1208831726/ruka2_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:17 +0000","from_user":"luka_m_bot","id_str":"41189756666777600","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u308f\u305f\u3057\u3082twitter\u306f\u3058\u3081\u307e\u3057\u305f","id":41189756666777600,"from_user_id":196059029,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://www24.atpages.jp/aoi2/bot.php" rel="nofollow">\u5de1\u308b\u97f3</a>"},{"from_user_id_str":"88135613","profile_image_url":"http://a3.twimg.com/profile_images/1088552877/P9280150_normal.JPG","created_at":"Fri, 25 Feb 2011 17:36:14 +0000","from_user":"Roko38","id_str":"41189740321587200","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\uff46\uff42\u306b\u30ed\u30b0\u30a4\u30f3\u3059\u308b\u6a5f\u4f1a\u304c\u65e5\u306b\u65e5\u306b\u5897\u3048\u3066\u304d\u305f\uff3e\uff3e \u6163\u308c\u3066\u304f\u308b\u3068\u3042\u3063\u3061\u306e\u304c\u9762\u767d\u3044\uff06\u4f7f\u3044\u52dd\u624b\u304c\u3044\u3044\u3088\u3046\u306a\u6c17\u304c\u3059\u308b\u3002\u8907\u5408\u7684\u306b\u8272\u3005\u51fa\u6765\u307e\u3059\u3088\u306d\u2026\u3063\u3066\u3001\u601d\u3063\u305f\u3053\u3068\u3092\u545f\u304f\u306e\u306fTwitter\u3060\u3063\u305f\u308a\u3067\u3059\u304c\u2026(^_^; \u305d\u3057\u3066\u81ea\u5206\u306e\u5834\u5408\u306f\u30c4\u30a4\u3068\u9023\u52d5\u3057\u3065\u3089\u3044\u72b6\u6cc1\u3060\u3063\u305f\u308a\u3067\u2026\u3002","id":41189740321587200,"from_user_id":88135613,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"110825211","profile_image_url":"http://a2.twimg.com/profile_images/1108977866/o_t_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:12 +0000","from_user":"kou_nanjyo","id_str":"41189731941363712","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @x68k: \u57fa\u672c\u7684\u306bTwitter\u4e0a\u3067\u306f"\u597d\u304d\u306b\u3084\u308c\u3070\u3044\u3044"\u3060\u3051\u3069\u3001\u540d\u524d\u3082\u30a2\u30a4\u30b3\u30f3\u3082\u30a2\u30f3\u30bf\u3058\u3083\u306a\u3044\u305f\u304f\u3055\u3093\u306e\u4eba\u305f\u3061\u306e\u9b42\u304c\u3053\u3082\u3063\u305f\u3082\u306e\u306a\u306e\u3060\u304b\u3089\u3001\u305d\u308c\u3060\u3051\u306f"\u80cc\u8ca0\u3048"\u3068\u601d\u3046\uff1e\u30ad\u30e3\u30e9\u30af\u30bf\u30fc\u30a2\u30ab\u30a6\u30f3\u30c8","id":41189731941363712,"from_user_id":110825211,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://tweetlogix.com" rel="nofollow">Tweetlogix</a>"},{"from_user_id_str":"2095960","profile_image_url":"http://a2.twimg.com/profile_images/1248999075/majiresu2_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:10 +0000","from_user":"guldeen","id_str":"41189726945947648","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3042\u308a\u3083\u307e\u3041\u3002\u25bchttp://bit.ly/et4vVa \uff3b\u89d2\u5ddd\u66f8\u5e97\uff3d\u300c\u30b6\u30fb\u30b9\u30cb\u30fc\u30ab\u30fc\u300d\u4f11\u520a\u3078\u3000\u300c\u6dbc\u5bae\u30cf\u30eb\u30d2\u300d\u751f\u3093\u3060\u30e9\u30ce\u30d9\u96d1\u8a8c18\u5e74\u3067\u5e55 via http://twitter.com/lkj777","id":41189726945947648,"from_user_id":2095960,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/">web</a>"},{"from_user_id_str":"164121549","profile_image_url":"http://a1.twimg.com/profile_images/1251758789/m_108-07ae3_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:09 +0000","from_user":"hachi_touhi","id_str":"41189719299727360","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30cd\u30bf\u30d0\u30ec\u6c17\u306b\u3057\u3066\u305f\u3089Twitter\u3084\u3063\u3066\u3089\u308c\u306a\u3044ww","id":41189719299727360,"from_user_id":164121549,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twicca.r246.jp/" rel="nofollow">twicca</a>"},{"from_user_id_str":"194494659","profile_image_url":"http://a3.twimg.com/profile_images/1249717822/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:36:08 +0000","from_user":"tomonattomo","id_str":"41189715415801856","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3046\u308f\u3001\u660e\u65e5\u671d\u304b\u3089\u30d0\u30a4\u30c8\u3084\u306e\u306b\u306a\u3093\u3060\u3053\u306e\u306d\u3075\u304b\u3057\u3002\u3042\u3001\u591c\u66f4\u304b\u3057\u3002\u30d1\u30d4\u30eb\u30b9\u3068BUMP\u3001\u3048\u307f\u3068Twitter\u306eDM\u3057\u3059\u304e\u305f\u306a\u2026","id":41189715415801856,"from_user_id":194494659,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://mixi.jp/promotion.pl?id=voice_twitter" rel="nofollow"> mixi \u30dc\u30a4\u30b9 </a>"},{"from_user_id_str":"97224364","profile_image_url":"http://a3.twimg.com/profile_images/1150074355/fb8bcca60d340862c053a756377bfae8_normal.jpeg","created_at":"Fri, 25 Feb 2011 17:36:06 +0000","from_user":"xxxheat","id_str":"41189709174677504","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Twitter\u5b8c\u5168\u306b\u30d0\u30b0\u3063\u3066\u308borz","id":41189709174677504,"from_user_id":97224364,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"<a href="http://twitter.com/" rel="nofollow">Twitter for iPhone</a>"}],"max_id":41190705623732224,"since_id":38643906774044672,"refresh_url":"?since_id=41190705623732224&q=twitter","next_page":"?page=2&max_id=41190705623732224&rpp=100&lang=ja&q=twitter","results_per_page":100,"page":1,"completed_in":0.093336,"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":"41190705623732224","query":"twitter"}
highjson.cabal view
@@ -1,39 +1,34 @@ name: highjson-version: 0.2.0.2-synopsis: Very fast JSON serialisation and parsing library-description: Low boilerplate, easy to use and very fast JSON serialisation and parsing+version: 0.3.0.0+synopsis: Spec based JSON parsing/serialisation+description: Low boilerplate, easy to use and very fast JSON serialisation and parsing without generics or TemplateHaskell homepage: https://github.com/agrafix/highjson bug-reports: https://github.com/agrafix/highjson/issues license: MIT license-file: LICENSE author: Alexander Thiemann <mail@athiemann.net> maintainer: Alexander Thiemann <mail@athiemann.net>-copyright: (c) 2015 Alexander Thiemann+copyright: (c) 2015 - 2017 Alexander Thiemann category: Text, Web, JSON build-type: Simple stability: experimental cabal-version: >=1.10-tested-with: GHC==7.8.3, GHC==7.10.1+tested-with: GHC==8.0.1 extra-source-files:- README.md bench/json-data/*.json library- exposed-modules: Data.Json.Parser- Data.Json.Serialiser- Data.Json- build-depends: base >=4.7 && <5,- attoparsec >=0.12.0.0,- bytestring >=0.10.4.0,- containers,- unordered-containers >=0.2.5,- vector >=0.7.1,- text >=1.1.1,- hashable >=1.1.2,- scientific >=0.3.3,- hvect >=0.2,- buffer-builder >=0.2.4+ exposed-modules:+ Data.HighJson+ other-modules:+ Data.HighJson.Types+ build-depends:+ aeson >= 1.0,+ base >=4.8 && <5,+ hvect >=0.2,+ text >=1.1.1,+ lens hs-source-dirs: src default-language: Haskell2010 @@ -42,20 +37,18 @@ hs-source-dirs: test main-is: Main.hs other-modules:- Data.Json.ParserSpec+ Data.JsonSpec build-depends:- base,- hspec >= 2.0,- highjson,- text,- QuickCheck >=2.8+ QuickCheck >=2.8,+ base,+ highjson,+ aeson,+ hspec >= 2.0,+ text,+ lens default-language: Haskell2010 ghc-options: -Wall -fno-warn-orphans -source-repository head- type: git- location: git://github.com/agrafix/highjson.git- benchmark highjson-benchmarks type: exitcode-stdio-1.0 ghc-options: -Wall -O2@@ -63,10 +56,14 @@ default-language: Haskell2010 main-is: Twitter.hs build-depends:- base,- criterion >=1.1,- aeson >=0.8,- highjson,- text,- deepseq,- bytestring+ aeson >=0.8,+ base,+ bytestring,+ criterion >=1.1,+ deepseq,+ highjson,+ text++source-repository head+ type: git+ location: git://github.com/agrafix/highjson.git
+ src/Data/HighJson.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RankNTypes #-}+module Data.HighJson+ ( -- * A json specification for any type+ HighSpec(..)+ -- * Construct specifications for records+ , recSpec, RecordFields(..), reqField, (.=), optField, (.=?)+ -- * Construct specifications for sum types+ , sumSpec, SumOptions(..), sumOpt, (.->)+ -- * Generate json serializers/encoders and parsers from specs+ , jsonSerializer, jsonEncoder, jsonParser+ -- * Specification structures+ , BodySpec(..)+ , RecordField(..), RecordSpec(..)+ , SumOption(..), SumSpec(..)+ -- * Aeson reexports+ , ToJSON(..), FromJSON(..)+ )+where++import Data.HighJson.Types++import Control.Lens hiding ((.=))+import Data.Aeson ((.:), (.:?), FromJSON(..), ToJSON(..))+import qualified Data.HVect as HV+import qualified Data.Text as T++reqField :: FromJSON f => T.Text -> (t -> f) -> RecordField t f+reqField jsonKey g =+ RecordField+ { rf_jsonKey = jsonKey+ , rf_optional = False+ , rf_jsonLoader = (.:)+ , rf_get = g+ }++(.=) :: FromJSON f => T.Text -> (t -> f) -> RecordField t f+jsonKey .= reader = reqField jsonKey reader++optField :: FromJSON f => T.Text -> (t -> Maybe f) -> RecordField t (Maybe f)+optField jsonKey g =+ RecordField+ { rf_jsonKey = jsonKey+ , rf_optional = True+ , rf_jsonLoader = (.:?)+ , rf_get = g+ }++(.=?) :: FromJSON f => T.Text -> (t -> Maybe f) -> RecordField t (Maybe f)+name .=? reader = optField name reader++sumOpt :: T.Text -> Prism' t o -> SumOption t o+sumOpt jsonKey p =+ SumOption+ { so_jsonKey = jsonKey+ , so_prism = p+ }++(.->) :: T.Text -> Prism' t o -> SumOption t o+jsonKey .-> p = sumOpt jsonKey p++recSpec :: T.Text -> Maybe T.Text -> HV.HVectElim flds t -> RecordFields t flds -> HighSpec t flds+recSpec name mDesc mk fields =+ HighSpec+ { hs_name = name+ , hs_description = mDesc+ , hs_bodySpec =+ BodySpecRecord $ RecordSpec (HV.uncurry mk) fields+ }++sumSpec :: T.Text -> Maybe T.Text -> SumOptions t flds -> HighSpec t flds+sumSpec name mDesc opts =+ HighSpec+ { hs_name = name+ , hs_description = mDesc+ , hs_bodySpec = BodySpecSum $ SumSpec opts+ }
+ src/Data/HighJson/Types.hs view
@@ -0,0 +1,153 @@+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Data.HighJson.Types+ ( HighSpec(..)+ , BodySpec(..)+ , RecordFields(..), RecordField(..), RecordSpec(..)+ , SumOptions(..), SumOption(..), SumSpec(..)+ , jsonSerializer, jsonEncoder, jsonParser+ )+where++import Control.Applicative+import Control.Lens hiding ((.=))+import Control.Monad+import Data.Aeson+import Data.Aeson.Types hiding (parse)+import Data.HVect+import Data.Monoid+import qualified Data.Text as T++data HighSpec a as+ = HighSpec+ { hs_name :: !T.Text+ , hs_description :: !(Maybe T.Text)+ , hs_bodySpec :: !(BodySpec a as)+ }++data BodySpec a as+ = BodySpecRecord !(RecordSpec a as)+ | BodySpecSum !(SumSpec a as)++data RecordFields t fs where+ RFEmpty :: RecordFields t '[]+ (:+:) :: RecordField t f -> RecordFields t fs -> RecordFields t (f ': fs)++infixr 5 :+:++data RecordField t f+ = RecordField+ { rf_jsonKey :: !T.Text+ , rf_optional :: !Bool+ , rf_jsonLoader :: Object -> T.Text -> Parser f+ , rf_get :: !(t -> f)+ }++data RecordSpec a fs+ = RecordSpec+ { rs_make :: HVect fs -> a+ , rs_fields :: RecordFields a fs+ }++data SumOptions t os where+ SOEmpty :: SumOptions t '[]+ (:|:) :: SumOption t o -> SumOptions t os -> SumOptions t (o ': os)++infixr 5 :|:++data SumOption t o+ = SumOption+ { so_jsonKey :: !T.Text+ , so_prism :: !(Prism' t o)+ }++data SumSpec a os+ = SumSpec+ { ss_options :: SumOptions a os+ }++jsonSerializer :: AllHave ToJSON as => HighSpec a as -> a -> Value+jsonSerializer hs val =+ object $ fst $+ case hs_bodySpec hs of+ BodySpecSum s -> jsonSerSum s val+ BodySpecRecord r -> jsonSerRec r val++jsonEncoder :: AllHave ToJSON as => HighSpec a as -> a -> Encoding+jsonEncoder hs val =+ pairs $ snd $+ case hs_bodySpec hs of+ BodySpecSum s -> jsonSerSum s val+ BodySpecRecord r -> jsonSerRec r val++jsonSerSum :: forall a as. AllHave ToJSON as => SumSpec a as -> a -> ([Pair], Series)+jsonSerSum (SumSpec sopts) val =+ loop sopts+ where+ loop ::+ forall fs. AllHave ToJSON fs => SumOptions a fs -> ([Pair], Series)+ loop flds =+ case flds of+ SOEmpty -> ([], mempty)+ f :|: fs ->+ case val ^? so_prism f of+ Just body ->+ let pair = (so_jsonKey f, toJSON body)+ encoder = so_jsonKey f .= body+ in ([pair], encoder)+ Nothing -> loop fs++jsonSerRec :: forall a as. AllHave ToJSON as => RecordSpec a as -> a -> ([Pair], Series)+jsonSerRec (RecordSpec _ rflds) val =+ loop rflds ([], mempty)+ where+ loop ::+ forall fs. AllHave ToJSON fs+ => RecordFields a fs -> ([Pair], Series) -> ([Pair], Series)+ loop flds accum@(ps, encoding) =+ case flds of+ RFEmpty -> accum+ f :+: fs ->+ let pair = (rf_jsonKey f, toJSON $ rf_get f val)+ encoder = rf_jsonKey f .= rf_get f val+ in loop fs ((pair : ps), encoder <> encoding)++jsonParser :: AllHave FromJSON as => HighSpec a as -> Value -> Parser a+jsonParser hs =+ withObject (T.unpack $ hs_name hs) $ \obj ->+ case hs_bodySpec hs of+ BodySpecRecord r -> jsonParserRecord r obj+ BodySpecSum s -> jsonParserSum (hs_name hs) s obj++jsonParserRecord :: forall a as. AllHave FromJSON as => RecordSpec a as -> Object -> Parser a+jsonParserRecord (RecordSpec mk rflds) obj =+ mk <$> loop rflds+ where+ loop :: forall fs. AllHave FromJSON fs => RecordFields a fs -> Parser (HVect fs)+ loop flds =+ case flds of+ RFEmpty -> pure HNil+ f :+: fs ->+ let parse =+ rf_jsonLoader f obj (rf_jsonKey f)+ in do x <- parse+ xs <- loop fs+ pure (x :&: xs)++jsonParserSum :: forall a as. AllHave FromJSON as => T.Text -> SumSpec a as -> Object -> Parser a+jsonParserSum name (SumSpec sopts) obj =+ loop sopts+ where+ loop :: forall os. AllHave FromJSON os => SumOptions a os -> Parser a+ loop opts =+ case opts of+ SOEmpty ->+ fail $+ "Failed to parse as " ++ T.unpack name+ o :|: os ->+ let parse =+ liftM (so_prism o #) $ obj .: so_jsonKey o+ in parse <|> loop os
− src/Data/Json.hs
@@ -1,93 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE TypeOperators #-}-module Data.Json- ( -- * DSL to define JSON structure- JsonSpec(..), FieldSpec(..), FieldKey, P.reqKey, P.optKey, P.TypedKey- , (.=), (.=?)- -- * DSL to define JSON structure for sum types- , JsonSumSpec(..), (P..->), (P.<||>), (S..<-)- , -- * Make parsers and serialisers from spec- makeParser, makeSerialiser, makeSumParser, makeSumSerialiser- , S.ToJson(..), P.JsonReadable(..)- , -- * Run parsers / serialisers- P.parseJsonBs, P.parseJsonBsl, P.parseJsonT- , S.serialiseJsonBs, S.serialiseJsonBsl, S.serialiseJsonT- )-where--import Data.HVect-import Data.Typeable-import qualified Data.Json.Serialiser as S-import qualified Data.Json.Parser as P---- | Describes JSON parsing and serialisation of a Haskell type-data JsonSpec k (ts :: [*])- = JsonSpec- { j_constr :: !(HVectElim ts k)- , j_fields :: !(FieldSpec k ts)- }---- | Describes JSON parsing and serialisation of a list of fields-data FieldSpec k (ts :: [*]) where- EmptySpec :: FieldSpec k '[]- (:+:) :: (S.ToJson t, P.JsonReadable t, Typeable t) => !(FieldKey k t) -> !(FieldSpec k ts) -> FieldSpec k (t ': ts)--infixr 5 :+:---- | Describes a json key-data FieldKey k t- = FieldKey- { fk_tk :: !(P.TypedKey t)- , fk_sk :: !(S.SpecKey k t)- }---- | Construct a 'FieldKey' mapping a json key to a getter function-(.=) :: (S.ToJson t, P.JsonReadable t, Typeable t) => P.TypedKey t -> (k -> t) -> FieldKey k t-tk .= getter = FieldKey tk ((P.typedKeyKey tk) S..: getter)-{-# INLINE (.=) #-}---- | Construct a 'FieldKey' mapping a json key to a getter function of--- a 'Maybe' type. This allows to omit the key when generating json instead of--- setting it to null.-(.=?) :: (S.ToJson t, P.JsonReadable t, Typeable t) => P.TypedKey (Maybe t) -> (k -> Maybe t) -> FieldKey k (Maybe t)-tk .=? getter = FieldKey tk ((P.typedKeyKey tk) S..:? getter)-{-# INLINE (.=?) #-}---- | Construct a 'P.Parser' from 'JsonSpec' to implement 'P.JsonReadable' instances-makeParser :: JsonSpec k ts -> P.Parser k-makeParser spec = P.runParseSpec $ (j_constr spec) P.:$: (mkObjSpec $ j_fields spec)-{-# INLINE makeParser #-}--mkObjSpec :: FieldSpec k ts -> P.ObjSpec ts-mkObjSpec EmptySpec = P.ObjSpecNil-mkObjSpec (FieldKey k _ :+: xs) = k P.:&&: mkObjSpec xs---- | Construct a function from 'JsonSpec' to implement 'S.ToJson' instances-makeSerialiser :: JsonSpec k ts -> k -> S.Value-makeSerialiser spec = S.runSerSpec (S.SingleConstr $ mkSerSpec (j_fields spec))-{-# INLINE makeSerialiser #-}--mkSerSpec :: FieldSpec k ts -> S.SerObjSpec k ts-mkSerSpec EmptySpec = S.SerObjSpecNil-mkSerSpec (FieldKey _ getter :+: xs) = getter S.:&&&: mkSerSpec xs---- | Describes JSON parsing and serialisation of a Haskell sum type. Currently--- the library can only guarantee matching parsers/serialisers for--- non-sum types using 'JsonSpec'.-data JsonSumSpec k- = JsonSumSpec- { js_parser :: !(P.ParseSpec k)- , js_serialiser :: !(k -> S.KeyedSerialiser k)- }---- | Construct a 'P.Parser' from 'JsonSumSpec' to implement 'P.JsonReadable' instances-makeSumParser :: JsonSumSpec k -> P.Parser k-makeSumParser = P.runParseSpec . js_parser-{-# INLINE makeSumParser #-}---- | Construct a function from 'JsonSumSpec' to implement 'S.ToJson' instances-makeSumSerialiser :: JsonSumSpec k -> k -> S.Value-makeSumSerialiser s = S.runSerSpec (S.MultiConstr (js_serialiser s))-{-# INLINE makeSumSerialiser #-}
− src/Data/Json/Parser.hs
@@ -1,381 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE OverlappingInstances #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeFamilies #-}-module Data.Json.Parser- ( -- * Parsing from different types- parseJsonBs, parseJsonBsl, parseJsonT- -- * Description how to parse JSON to a Haskell type- , JsonReadable(..)- -- * DSL to easily create parser for custom Haskell types- , runParseSpec, ObjSpec(..), ParseSpec(..), KeyedConstr, (.->), (<||>)- , ConstrTagger, ResultType- , TypedKey, reqKey, optKey, typedKeyKey- -- * Low level JSON parsing helpers- , readObject, Parser, WrappedValue(..), getValueByKey, getOptValueByKey- )-where--import Control.Applicative-import Control.Monad-import Data.Attoparsec.ByteString.Char8-import Data.HVect-import Data.Int-import Data.Maybe-import Data.Scientific hiding (scientific)-import Data.String-import Data.Typeable-import Data.Word-import Prelude hiding (uncurry, take)-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as BSL-import qualified Data.HashMap.Strict as HM-import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import qualified Data.Vector as V---- | Parse json from a strict 'BS.ByteString'-parseJsonBs :: JsonReadable t => BS.ByteString -> Either String t-parseJsonBs = parseOnly (readJson <* skipSpace <* endOfInput)-{-# INLINE parseJsonBs #-}---- | Parse json from a lazy 'BSL.ByteString'-parseJsonBsl :: JsonReadable t => BSL.ByteString -> Either String t-parseJsonBsl = parseJsonBs . BSL.toStrict-{-# INLINE parseJsonBsl #-}---- | Parse json from a strict 'T.Text'-parseJsonT :: JsonReadable t => T.Text -> Either String t-parseJsonT = parseJsonBs . T.encodeUtf8-{-# INLINE parseJsonT #-}---- | Typeclass defining an attoparsec 'Parser' how Haskell types should--- be parsed from JSON. Use predifined instances (with 'readJson') and--- 'runSpec' (on 'ObjSpec') to define instances for custom types-class JsonReadable t where- readJson :: Parser t--instance JsonReadable t => JsonReadable [t] where- readJson = readJList readJson--instance JsonReadable t => JsonReadable (V.Vector t) where- readJson = liftM V.fromList readJson--readJList :: Parser t -> Parser [t]-readJList parseEl =- do skipSpace- char '['- vals <- parseEl `sepBy'` (skipSpace >> char ',')- skipSpace- char ']'- return vals-{-# INLINE readJList #-}--readTuple :: JsonReadable t => Parser (t, t)-readTuple =- do xs <- readJson- case xs of- (a : b : _) -> return (a, b)- _ -> fail "Not a tuple!"-{-# INLINE readTuple #-}--instance JsonReadable t => JsonReadable (t, t) where- readJson = readTuple--instance JsonReadable Bool where- readJson = readBool--readBool :: Parser Bool-readBool =- do skipSpace- True <$ string "true" <|> False <$ string "false"-{-# INLINE readBool #-}--instance JsonReadable Scientific where- readJson = skipSpace >> scientific--instance JsonReadable Double where- readJson = readDouble--readDouble :: Parser Double-readDouble = liftM toRealFloat readJson-{-# INLINE readDouble #-}--instance JsonReadable Int where- readJson = readBoundedInteger--instance JsonReadable Int8 where- readJson = readBoundedInteger--instance JsonReadable Int16 where- readJson = readBoundedInteger--instance JsonReadable Int32 where- readJson = readBoundedInteger--instance JsonReadable Int64 where- readJson = readBoundedInteger--instance JsonReadable Word where- readJson = readBoundedInteger--instance JsonReadable Word8 where- readJson = readBoundedInteger--instance JsonReadable Word16 where- readJson = readBoundedInteger--instance JsonReadable Word32 where- readJson = readBoundedInteger--instance JsonReadable Word64 where- readJson = readBoundedInteger--readBoundedInteger :: (Integral i, Bounded i) => Parser i-readBoundedInteger =- do mRes <- liftM toBoundedInteger readJson- case mRes of- Nothing -> fail "input is not a bounded integer"- Just val -> return val-{-# INLINE readBoundedInteger #-}--instance JsonReadable T.Text where- readJson = readText--readText :: Parser T.Text-readText =- do skipSpace- char '"'- txt <-- scan False $ \s c ->- if s- then Just False- else if c == '"'- then Nothing- else Just (c == '\\')- char '"'- case T.decodeUtf8' txt of- Right r -> return r- Left msg -> fail $ show msg-{-# INLINE readText #-}--instance JsonReadable t => JsonReadable (Maybe t) where- readJson = readMaybe--readNull :: Parser ()-readNull = () <$ string "null"-{-# INLINE readNull #-}--readMaybe :: JsonReadable t => Parser (Maybe t)-readMaybe =- do skipSpace- Nothing <$ readNull <|> Just <$> readJson-{-# INLINE readMaybe #-}--instance (JsonReadable a, JsonReadable b) => JsonReadable (Either a b) where- readJson = readEither--readEither :: (JsonReadable a, JsonReadable b) => Parser (Either a b)-readEither =- Left <$> readJson <|> Right <$> readJson-{-# INLINE readEither #-}---- | A value that is 'Typeable' and 'JsonReadable'-data WrappedValue- = forall t. (Typeable t, JsonReadable t) => WrappedValue !t--readAnyJsonVal :: Parser ()-readAnyJsonVal =- () <$ readObject (const Nothing)- <|> () <$ readBool- <|> () <$ readText- <|> () <$ readNull- <|> () <$ (skipSpace >> scientific)- <|> () <$ readJList readAnyJsonVal-{-# INLINE readAnyJsonVal #-}--instance JsonReadable a => JsonReadable (HVect '[a]) where- readJson = liftM singleton readJson---- | Parse a json object given a value parser for each key-readObject :: (T.Text -> Maybe (Parser a)) -> Parser (HM.HashMap T.Text a)-readObject getKeyParser =- do skipSpace- char '{'- vals <- kvLoop- skipSpace- char '}'- skipSpace- return $! vals- where- kvLoop =- do skipSpace- val <- parseKv- skipSpace- ch <- peekChar'- hm <-- if ch == ','- then do char ','- kvLoop- else return HM.empty- return $- case val of- Just (k, v) -> HM.insert k v hm- Nothing -> hm- parseKv =- do k <- readText- skipSpace- char ':'- case getKeyParser k of- Nothing ->- do readAnyJsonVal- return Nothing- Just parser -> Just <$> ((,) <$> pure k <*> parser)-{-# INLINE readObject #-}---- | Get a value out of the map returned by 'readObject'-getValueByKey :: (Monad m, Typeable t) => T.Text -> HM.HashMap T.Text WrappedValue -> m t-getValueByKey key hm =- do optVal <- getOptValueByKey key hm- case optVal of- Nothing -> fail ("Key " ++ show key ++ " not present")- Just val -> return val-{-# INLINE getValueByKey #-}---- | Optionally get a value out of the map returned by 'readObject'-getOptValueByKey :: (Monad m, Typeable t) => T.Text -> HM.HashMap T.Text WrappedValue -> m (Maybe t)-getOptValueByKey key hm =- case HM.lookup key hm of- Just (WrappedValue x) ->- case cast x of- Just val -> return (Just val)- Nothing -> fail "Invalid wrapped type"- Nothing -> return Nothing-{-# INLINE getOptValueByKey #-}--type KeyReader t =- Monad m => T.Text -> HM.HashMap T.Text WrappedValue -> m t---- | Json object key to a value t-data TypedKey t =- TypedKey !(KeyReader t) !T.Text---- | Get the textual key of a 'TypedKey'-typedKeyKey :: TypedKey t -> T.Text-typedKeyKey (TypedKey _ t) = t-{-# INLINE typedKeyKey #-}---- | Required json object key. Use 'IsString' instance for automatic choice-reqKey :: Typeable t => T.Text -> TypedKey t-reqKey = TypedKey getValueByKey-{-# INLINE reqKey #-}---- | Optional json object key. Use 'IsString' instance for automatic choice-optKey :: Typeable t => T.Text -> TypedKey (Maybe t)-optKey =- TypedKey optGetter- where- optGetter k hm =- do mOpt <- getOptValueByKey k hm- return $ join mOpt-{-# INLINE optKey #-}--instance Typeable t => IsString (TypedKey (Maybe t)) where- fromString = optKey . T.pack--instance Typeable t => IsString (TypedKey t) where- fromString = reqKey . T.pack---- | Associates a json key with a parser-data KeyedConstr k- = KeyedConstr- { kc_key :: !T.Text- , kc_parser :: !(Parser k)- }--class ConstrTagger r where- type ResultType r :: *- -- | Associate a json key with a parser- (.->) :: T.Text -> Parser (ResultType r) -> r--instance ConstrTagger (KeyedConstr k) where- type ResultType (KeyedConstr k) = k- key .-> parser = KeyedConstr key parser--instance ConstrTagger (ParseSpec k) where- type ResultType (ParseSpec k) = k- key .-> parser = FirstConstr (KeyedConstr key parser)---- | Parser specification. Use ':$:' for normal types and 'FirstConstr' / ':|:' for sum types-data ParseSpec k where- (:$:) :: HVectElim ts k -> ObjSpec ts -> ParseSpec k- FirstConstr :: KeyedConstr k -> ParseSpec k- (:|:) :: KeyedConstr k -> ParseSpec k -> ParseSpec k--infixr 4 :$:-infixr 3 <||>---- | Choice between multiple constructors-(<||>) :: KeyedConstr k -> ParseSpec k -> ParseSpec k-(<||>) = (:|:)-{-# INLINE (<||>) #-}---- | Convert a 'ParseSpec' into a 'Parser'-runParseSpec :: ParseSpec k -> Parser k-runParseSpec x =- case x of- constr :$: spec ->- runSpec constr spec- FirstConstr (KeyedConstr key parser) ->- let keyGetter reqKey =- if reqKey == key- then Just parser- else Nothing- in do hm <- readObject keyGetter- case HM.lookup key hm of- Nothing -> fail ("Missing key " ++ show key)- Just x -> return x- constr :|: next ->- runParseSpec (FirstConstr constr) <|> runParseSpec next---- | List of 'TypedKey's, should be in the same order as your--- constructor in 'runSpec' will expect them-data ObjSpec (ts :: [*]) where- ObjSpecNil :: ObjSpec '[]- (:&&:) :: (JsonReadable t, Typeable t) => !(TypedKey t) -> !(ObjSpec ts) -> ObjSpec (t ': ts)--infixr 5 :&&:--type CompiledSpec m ts =- (HM.HashMap T.Text WrappedValue -> m (HVect ts), T.Text -> Maybe (Parser WrappedValue))--compileSpec :: Monad m => ObjSpec ts -> CompiledSpec m ts-compileSpec ObjSpecNil = (const (return HNil), const Nothing)-compileSpec ((TypedKey keyReader key :: TypedKey t) :&&: xs) =- let (nextHmFun, nextParserFun) = compileSpec xs- in ( \hm ->- do el <- keyReader key hm- xs <- nextHmFun hm- return (el :&: xs)- , \lookupKey ->- if lookupKey == key- then Just $! liftM WrappedValue (readJson :: Parser t)- else nextParserFun lookupKey- )---- | Convert an 'ObjSpec' into a 'Parser' provided a constructor--- function for defining 'JsonReadable' instances.-runSpec :: HVectElim ts x -> ObjSpec ts -> Parser x-runSpec mkVal spec =- do let (mkTyVect, kv) = compileSpec spec- !hm <- readObject kv- !vect <- mkTyVect hm- return $! uncurry mkVal vect
− src/Data/Json/Serialiser.hs
@@ -1,120 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE TypeOperators #-}-module Data.Json.Serialiser- ( -- * Serialising to different types- serialiseJsonBs, serialiseJsonBsl, serialiseJsonT- -- * Description how to serialise JSON from a Haskell type- , ToJson(..)- -- * DSL to easily create serialiser for custom Haskell types- , runSerSpec, SerSpec(..), (.<-), KeyedSerialiser, SerObjSpec(..)- , SpecKey, (.:), (.:?)- -- * Low level JSON serialising helpers- , ObjectBuilder, emptyObject, Value, (.=), (.=#), row, array, nullValue- )-where--import Data.BufferBuilder.Json-import Data.Int-import Data.Monoid-import Data.Typeable-import qualified Data.ByteString as BS-import qualified Data.ByteString.Lazy as BSL-import qualified Data.Text as T-import qualified Data.Text.Encoding as T--instance (ToJson a, ToJson b) => ToJson (Either a b) where- toJson x =- case x of- Left y -> toJson y- Right z -> toJson z--instance (ToJson a, ToJson b) => ToJson (a, b) where- toJson (x, y) = toJson [ toJson x, toJson y ]--instance ToJson Int64 where- toJson i =- let j :: Int- j = fromIntegral i- in toJson j---- | A json key and a getter-data SpecKey k t- = SpecKey- { k_key :: !T.Text- , k_getVal :: !(k -> Maybe t)- }---- | Construct a 'SpecKey' mapping a json key to a getter function-(.:) :: (ToJson t, Typeable t) => T.Text -> (k -> t) -> SpecKey k t-k .: getter = SpecKey k (Just . getter)-{-# INLINE (.:) #-}---- | Construct a 'SpecKey' mapping a json key to a getter function of--- a 'Maybe' type. This allows to omit the key when generating json instead of--- setting it to null.-(.:?) :: (ToJson t, Typeable t) => T.Text -> (k -> Maybe t) -> SpecKey k (Maybe t)-k .:? getter =- SpecKey k $ \obj ->- let val = getter obj- in case val of- Nothing -> Nothing- Just _ -> Just val-{-# INLINE (.:?) #-}--newtype KeyedSerialiser k- = KeyedSerialiser { unKeyedSerialiser :: Value }---- | Associate a JSON key with a serialiser-(.<-) :: ToJson a => T.Text -> a -> KeyedSerialiser k-a .<- b = KeyedSerialiser $ toJson (a .= b)-{-# INLINE (.<-) #-}---- | Parser specification. Use 'OnlyConstr' for normal types and 'FirstConstr'/'NextConstr' for sum types-data SerSpec k where- SingleConstr :: SerObjSpec k ts -> SerSpec k- MultiConstr :: (k -> KeyedSerialiser k) -> SerSpec k--runSerSpec :: SerSpec k -> k -> Value-runSerSpec spec input =- case spec of- SingleConstr fullSpec -> runSerObjSpec fullSpec input- MultiConstr getVal -> unKeyedSerialiser $ getVal input-{-# INLINE runSerSpec #-}---- | List of 'SpecKey's defining the serialisation of values to json-data SerObjSpec k (ts :: [*]) where- SerObjSpecNil :: SerObjSpec k '[]- (:&&&:) :: (ToJson t, Typeable t) => !(SpecKey k t) -> !(SerObjSpec k ts) -> SerObjSpec k (t ': ts)--infixr 5 :&&&:---- | Convert a 'SerObjSpec' into an 'Value' for defining 'ToJson' instances-runSerObjSpec :: SerObjSpec k ts -> k -> Value-runSerObjSpec spec input = toJson (buildSpec spec input)-{-# INLINE runSerObjSpec #-}--buildSpec :: SerObjSpec k ts -> k -> ObjectBuilder-buildSpec spec input =- case spec of- SerObjSpecNil -> mempty- (SpecKey key getVal :&&&: xs) ->- case getVal input of- Nothing -> buildSpec xs input- Just val -> key .= getVal input <> buildSpec xs input---- | Serialise json to a strict 'BS.ByteString'-serialiseJsonBs :: ToJson a => a -> BS.ByteString-serialiseJsonBs = encodeJson-{-# INLINE serialiseJsonBs #-}---- | Serialise json to a lazy 'BSL.ByteString'-serialiseJsonBsl :: ToJson a => a -> BSL.ByteString-serialiseJsonBsl = BSL.fromStrict . serialiseJsonBs-{-# INLINE serialiseJsonBsl #-}---- | Serialise json to a strict 'T.Text'-serialiseJsonT :: ToJson a => a -> T.Text-serialiseJsonT = T.decodeUtf8 . serialiseJsonBs-{-# INLINE serialiseJsonT #-}
− test/Data/Json/ParserSpec.hs
@@ -1,83 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DeriveDataTypeable #-}-module Data.Json.ParserSpec where--import Data.Json.Parser--import Control.Applicative-import Data.Typeable-import qualified Data.Text as T-import Test.Hspec--data SomeDummy- = SomeDummy- { sd_int :: Int- , sd_bool :: Bool- , sd_text :: T.Text- , sd_either :: Either Bool T.Text- , sd_maybe :: Maybe Int- } deriving (Show, Eq)--instance JsonReadable SomeDummy where- readJson =- runParseSpec $ SomeDummy :$: "int" :&&: "bool" :&&: "text" :&&: "either" :&&: "maybe" :&&: ObjSpecNil--data SomeNested- = SomeNested- { sn_list :: [SomeNested]- , sn_obj :: Maybe SomeNested- } deriving (Show, Eq, Typeable)--instance JsonReadable SomeNested where- readJson =- runParseSpec $ SomeNested :$: "list" :&&: "obj" :&&: ObjSpecNil--data Foo- = Foo- { f_fooVal :: Int- } deriving (Show, Eq)--instance JsonReadable Foo where- readJson =- runParseSpec $ Foo :$: "value" :&&: ObjSpecNil--data Bar- = Bar- { b_barVal :: Int- } deriving (Show, Eq)--instance JsonReadable Bar where- readJson =- runParseSpec $ Bar :$: "value" :&&: ObjSpecNil--data SumType- = SumFoo Foo- | SumBar Bar- deriving (Show, Eq)--instance JsonReadable SumType where- readJson =- runParseSpec $- "foo" .-> (SumFoo <$> readJson)- <||> "bar" .-> (SumBar <$> readJson)--spec :: Spec-spec =- describe "Parser" $- do it "Handles custom types correctly" $- do parseJsonBs "{\"int\": 34, \"text\": \"Teext\", \"bool\": true, \"either\": false}"- `shouldBe` Right (SomeDummy 34 True "Teext" (Left False) Nothing)- parseJsonBs "{\"int\": 34, \"text\": \"Teext\", \"bool\": true, \"either\": \"ok\", \"maybe\": 42}"- `shouldBe` Right (SomeDummy 34 True "Teext" (Right "ok") (Just 42))- it "Handles extra key correctly" $- parseJsonBs "{\"int\": 34, \"text\": \"Teext\", \"bool\": true, \"either\": false, \"extraKey\": false}"- `shouldBe` Right (SomeDummy 34 True "Teext" (Left False) Nothing)- it "Handles nested types correctly" $- do parseJsonBs "{\"list\": [{\"list\": []}], \"obj\": {\"list\": []}}"- `shouldBe` Right (SomeNested [SomeNested [] Nothing] (Just $ SomeNested [] Nothing))- it "Parses bools correctly" $- do parseJsonBs "true" `shouldBe` Right True- parseJsonBs "false" `shouldBe` Right False- it "Handles sum types correctly" $- do parseJsonBs "{\"foo\": {\"value\": 42}}" `shouldBe` Right (SumFoo (Foo 42))- parseJsonBs "{\"bar\": {\"value\": 42}}" `shouldBe` Right (SumBar (Bar 42))
+ test/Data/JsonSpec.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell #-}+module Data.JsonSpec where++import Data.HighJson++import Control.Lens.TH+import Data.Aeson (eitherDecode, encode)+import Data.Typeable+import Test.Hspec+import Test.QuickCheck+import qualified Data.Text as T++data SomeDummy+ = SomeDummy+ { sd_int :: Int+ , sd_bool :: Bool+ , sd_text :: T.Text+ , sd_either :: Either Bool T.Text+ , sd_maybe :: Maybe Int+ } deriving (Show, Eq)++someDummySpec :: HighSpec SomeDummy '[Int, Bool, T.Text, Either Bool T.Text, Maybe Int]+someDummySpec =+ recSpec "Some Dummy" Nothing SomeDummy $+ "int" .= sd_int+ :+: "bool" .= sd_bool+ :+: "text" .= sd_text+ :+: "either" .= sd_either+ :+: "maybe" .= sd_maybe+ :+: RFEmpty++instance ToJSON SomeDummy where+ toJSON = jsonSerializer someDummySpec+ toEncoding = jsonEncoder someDummySpec++instance FromJSON SomeDummy where+ parseJSON = jsonParser someDummySpec++newtype SomeText = SomeText { unSomeText :: T.Text }++instance Arbitrary SomeText where+ arbitrary = SomeText . T.pack <$> listOf1 (choose ('A', 'Z'))++instance Arbitrary SomeDummy where+ arbitrary =+ SomeDummy+ <$> arbitrary+ <*> arbitrary+ <*> (unSomeText <$> arbitrary)+ <*> ebt+ <*> arbitrary+ where+ ebt =+ do v <- arbitrary+ case v of+ Left b -> pure (Left b)+ Right (SomeText t) -> pure (Right t)++data SomeNested+ = SomeNested+ { sn_list :: [SomeNested]+ , sn_obj :: Maybe SomeNested+ } deriving (Show, Eq, Typeable)++someNestedSpec :: HighSpec SomeNested '[[SomeNested], Maybe SomeNested]+someNestedSpec =+ recSpec "Nested" Nothing SomeNested $+ "list" .= sn_list+ :+: "obj" .=? sn_obj+ :+: RFEmpty++instance ToJSON SomeNested where+ toJSON = jsonSerializer someNestedSpec+ toEncoding = jsonEncoder someNestedSpec++instance FromJSON SomeNested where+ parseJSON = jsonParser someNestedSpec++data SomeSumType+ = SomeDummyT SomeDummy+ | SomeInt Int+ | SomeBool Bool+ | SomeEnum+ deriving (Show, Eq, Typeable)++makePrisms ''SomeSumType++someSumSpec :: HighSpec SomeSumType '[SomeDummy, Int, Bool, ()]+someSumSpec =+ sumSpec "SomeSum" Nothing $+ "some_dummy" .-> _SomeDummyT+ :|: "some_int" .-> _SomeInt+ :|: "some_bool" .-> _SomeBool+ :|: "some_enum" .-> _SomeEnum+ :|: SOEmpty++instance ToJSON SomeSumType where+ toJSON = jsonSerializer someSumSpec+ toEncoding = jsonEncoder someSumSpec++instance FromJSON SomeSumType where+ parseJSON = jsonParser someSumSpec++instance Arbitrary SomeSumType where+ arbitrary =+ oneof+ [ SomeDummyT <$> arbitrary+ , SomeInt <$> arbitrary+ , SomeBool <$> arbitrary+ ]++data ParamType a+ = ParamType+ { pt_key :: a+ , pt_val :: T.Text+ } deriving (Show, Eq, Typeable)++paramTypeSpec :: FromJSON a => HighSpec (ParamType a) '[a, T.Text]+paramTypeSpec =+ recSpec "Some Param" Nothing ParamType $+ "key" .= pt_key+ :+: "val" .= pt_val+ :+: RFEmpty++instance (ToJSON a, FromJSON a) => ToJSON (ParamType a) where+ toJSON = jsonSerializer paramTypeSpec+ toEncoding = jsonEncoder paramTypeSpec++instance (FromJSON a) => FromJSON (ParamType a) where+ parseJSON = jsonParser paramTypeSpec++instance Arbitrary a => Arbitrary (ParamType a) where+ arbitrary =+ ParamType <$> arbitrary <*> (unSomeText <$> arbitrary)++spec :: Spec+spec =+ describe "Parser and Serialiser" $+ do it "Handles custom types correctly" $+ do let t1 = SomeDummy 34 True "Teext" (Left False) Nothing+ eitherDecode (encode t1) `shouldBe` Right t1+ let t2 = SomeDummy 34 True "Teext" (Right "ok") (Just 42)+ eitherDecode (encode t2) `shouldBe` Right t2+ it "Handles arbitrary custom types correctly" $ property $ \t ->+ (eitherDecode . encode) t == Right (t :: SomeDummy)+ it "Handles arbitrary custom sum types correctly" $ property $ \t ->+ (eitherDecode . encode) t == Right (t :: SomeSumType)+ it "Handles arbitrary custom parametrized types correctly" $ property $ \t ->+ (eitherDecode . encode) t == Right (t :: ParamType SomeSumType)+ it "Handles nested types correctly" $+ do let nested = SomeNested [SomeNested [] Nothing] (Just $ SomeNested [] Nothing)+ eitherDecode (encode nested) `shouldBe` Right nested
test/Main.hs view
@@ -1,1 +1,9 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover #-}+module Main where++import qualified Data.JsonSpec++import Test.Hspec++main :: IO ()+main = hspec $+ do Data.JsonSpec.spec