packages feed

mysql-haskell 0.8.4.3 → 1.2.5

raw patch · 94 files changed

Files

ChangeLog.md view
@@ -1,5 +1,131 @@ # Revision history for mysql-haskell +## 1.2.5 -- 2026.05.04++ Replace abandoned `pem` dependency with `crypton-pem` (#84)++## 1.2.4 -- 2026.04.20++ Fix benchmark compilation failures (#82):+  + Replace deleted `Data.Binary.Parser.Char8` import in benchmark with+    `Word8`-based combinators from `Data.Binary.Parser`+  + Replace `GHC.Prim`/`GHC.Types` imports with `GHC.Exts` from `base`+  + Fix `Word8#` vs `Word#` type mismatch in `mhDigitToInt`+  + Remove stale haddock reference to deleted `Char8` module++## 1.2.3 -- 2026.04.12++ Support caching_sha2_password full auth via RSA on non-TLS connections#81 thanks @ikaro1192++## 1.2.2 -- 2026.03.25++ Widen tls upper bound to allow tls 2.4.x++ Fix unsafe ByteString operations (`unsafeDrop`, `unsafeTail`, `unsafeIndex`)+  on untrusted wire protocol data that caused undefined behavior (segfaults,+  garbage reads) on malformed input. The safe alternatives are also O(1).+  Affected parsers: text protocol timestamp/datetime/time/date fields,+  NEWDECIMAL in binlog, and `eventHeaderLen` for unknown event types.++## 1.2.1 -- 2026.03.23++ Export `connectUnixSocket` function.++ Tweak cabal file to better handle crypton vs cryptonite.++ Fix version cut off for tls compatibility.++ Fix missing `liftA2` import when running tests on GHC 9.4.++ Add integration test for Unix socket.++## 1.2.0 -- 2026.03.07++ Add support for  caching_sha2_password authentiation.++## 1.1.9 -- 2026.03.07++ Fix binary protocol error 1210 on modern MySQL/MariaDB:+  `MYSQL_TYPE_BIT` and `MYSQL_TYPE_YEAR` are not valid parameter types+  for `COM_STMT_EXECUTE`. Send `MySQLBit` as `MYSQL_TYPE_LONGLONG`+  (unsigned, little-endian) and `MySQLYear` as `MYSQL_TYPE_SHORT`+  (unsigned, 2-byte integer) instead.++ Fix `MySQLYear` binary encoding: was sending a length-encoded string+  which caused data misalignment for all subsequent parameters.++ Fix version detection for MariaDB 10+/11+ (fractional seconds support).++ Fix CI: enable binary logging and grant binlog privileges for+  integration tests on MariaDB.++ Add roundtrip integration tests for `MySQLBit` and `MySQLYear`.++## 1.1.8++ bump constraints++## 1.1.7 -- 2025.08.23 ++ bump constraints++ upgrade cabal file++ add upper bounds to all the warnings+  + it was only the test suite so I made them broad.++ Disable inline-rule-shadowing for Int24 and Word24.+  those rules fire fine. you can test it our yourself with+  the Main.hs in the main repository.+  There is a stanza to do so in cabal.++ clean up cabal file a bit, use GHC2021++## 1.1.6 -- 2024.10.23 ++ bump constraints++## 1.1.5 -- 2024.06.25++ bump constraints++## 1.1.4 -- 2024.02.17 ++ bump constraints++## 1.1.3 -- 2023.08.30++ bump constraints++## 1.1.2 -- 2023.08.14+++ Fix package name of changelog++ Drop support for RC4 chipher which is depracated++ drop dependency on binary-ieee754, which was unused.++ Fix text 2 support, thanks @RikvanToor++## 1.1.1 -- 2023.08.14+++ cleaned up some warnings++ Merge back into mysql-haskell after gaining hackage access.++ Deprecate mysql-pure in favor of old hackage+  since it's only been out for a day this sort off+  stream lines upgrading for most applications.+  Cabal will just figure it out, rather then+  users having to "find" mysql-pure.+  I'll just make a bonus announcement to+  let people not depend on mysql-pure.++## 1.1.0 -- 2023.08.12 +There was a bunch of stuff unrelated to mysql+which I purged.+If you need any on these go depend on the +respective unmaintained package.+++ Delete module System.IO.Streams.UnixSocket++ Dleete module Data.Binary.Parser.Char8++ Delete module System.IO.Streams.Binary++## 1.0.2 -- 2023.08.12 ++ Bump dependencies, go all into crypton++ merge tcp-streams into the package++## 1.0.1 -- 2023.08.12 ++ add json testfiles as extra source files to make tests pass in nix builds++## 1.0.0 -- 2023.08.12 +++ Fork from mysql-haskell into mysql-pure++ add flake++ merge packages:+  + word24+  + binary-parsers+  + wirestreams+  +  This involved copying over all source files,+  furthermore I copied in all tests and benchmarks.+  The tests are now one giant test suite.+  I temporarly disabled the mysql tests as they need a mysql+  database to run which won't work nicely with CI right now.+  However you can run these locally by uncommenting that line.++ Add CI which relies on native cabal instead of stack++ Add an action to automatically bump version.++ Add nightly build cron job.+ ## 0.8.4.3 -- 2020-11-04  * Fix build with GHC 8.8.
− Database/MySQL/Base.hs
@@ -1,326 +0,0 @@-{-|-Module      : Database.MySQL.Base-Description : Prelude of mysql-haskell-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--This module provide common MySQL operations,--NOTEs on 'Exception's: This package use 'Exception' to deal with unexpected situations,-but you shouldn't try to catch them if you don't have a recovery plan,-for example: there's no meaning to catch a 'ERRException' during authentication unless you want to try different passwords.-By using this library you will meet:--    * 'NetworkException':  underline network is broken.-    * 'UnconsumedResultSet':  you should consume previous resultset before sending new command.-    * 'ERRException':  you receive a 'ERR' packet when you shouldn't.-    * 'UnexpectedPacket':  you receive a unexpected packet when you shouldn't.-    * 'DecodePacketException': there's a packet we can't decode.-    * 'WrongParamsCount': you're giving wrong number of params to 'renderParams'.--Both 'UnexpectedPacket' and 'DecodePacketException' may indicate a bug of this library rather your code, so please report!---}-module Database.MySQL.Base-    ( -- * Setting up and control connection-      MySQLConn-    , ConnectInfo(..)-    , defaultConnectInfo-    , defaultConnectInfoMB4-    , connect-    , connectDetail-    , close-    , ping-      -- * Direct query-    , execute-    , executeMany-    , executeMany_-    , execute_-    , query_-    , queryVector_-    , query-    , queryVector-      -- * Prepared query statement-    , prepareStmt-    , prepareStmtDetail-    , executeStmt-    , queryStmt-    , queryStmtVector-    , closeStmt-    , resetStmt-      -- * Helpers-    , withTransaction-    , QueryParam(..)-    , Param (..)-    , Query(..)-    , renderParams-    , command-    , Stream.skipToEof-      -- * Exceptions-    , NetworkException(..)-    , UnconsumedResultSet(..)-    , ERRException(..)-    , UnexpectedPacket(..)-    , DecodePacketException(..)-    , WrongParamsCount(..)-      -- * MySQL protocol-    , module  Database.MySQL.Protocol.Auth-    , module  Database.MySQL.Protocol.Command-    , module  Database.MySQL.Protocol.ColumnDef-    , module  Database.MySQL.Protocol.Packet-    , module  Database.MySQL.Protocol.MySQLValue-    ) where--import           Control.Applicative-import           Control.Exception                  (mask, onException, throwIO)-import           Control.Monad-import qualified Data.ByteString.Lazy               as L-import           Data.IORef                         (writeIORef)-import           Database.MySQL.Connection-import           Database.MySQL.Protocol.Auth-import           Database.MySQL.Protocol.ColumnDef-import           Database.MySQL.Protocol.Command-import           Database.MySQL.Protocol.MySQLValue-import           Database.MySQL.Protocol.Packet--import           Database.MySQL.Query-import           System.IO.Streams                  (InputStream)-import qualified System.IO.Streams                  as Stream-import qualified Data.Vector                        as V-------------------------------------------------------------------------------------- | Execute a MySQL query with parameters which don't return a result-set.------ The query may contain placeholders @?@, for filling up parameters, the parameters--- will be escaped before get filled into the query, please DO NOT enable @NO_BACKSLASH_ESCAPES@,--- and you should consider using prepared statement if this's not an one shot query.----execute :: QueryParam p => MySQLConn -> Query -> [p] -> IO OK-execute conn qry params = execute_ conn (renderParams qry params)--{-# SPECIALIZE execute :: MySQLConn -> Query -> [MySQLValue] -> IO OK #-}-{-# SPECIALIZE execute :: MySQLConn -> Query -> [Param]      -> IO OK #-}---- | Execute a multi-row query which don't return result-set.------ Leverage MySQL's multi-statement support to do batch insert\/update\/delete,--- you may want to use 'withTransaction' to make sure it's atomic, and--- use @sum . map okAffectedRows@ to get all affected rows count.------ @since 0.2.0.0----executeMany :: QueryParam p => MySQLConn -> Query -> [[p]] -> IO [OK]-executeMany conn@(MySQLConn is os _ _) qry paramsList = do-    guardUnconsumed conn-    let qry' = L.intercalate ";" $ map (fromQuery . renderParams qry) paramsList-    writeCommand (COM_QUERY qry') os-    mapM (\ _ -> waitCommandReply is) paramsList--{-# SPECIALIZE executeMany :: MySQLConn -> Query -> [[MySQLValue]] -> IO [OK] #-}-{-# SPECIALIZE executeMany :: MySQLConn -> Query -> [[Param]]      -> IO [OK] #-}---- | Execute multiple querys (without param) which don't return result-set.------ This's useful when your want to execute multiple SQLs without params, e.g. from a--- SQL dump, or a table migration plan.------ @since 0.8.4.0----executeMany_ :: MySQLConn -> Query -> IO [OK]-executeMany_ conn@(MySQLConn is os _ _) qry = do-    guardUnconsumed conn-    writeCommand (COM_QUERY (fromQuery qry)) os-    waitCommandReplys is---- | Execute a MySQL query which don't return a result-set.----execute_ :: MySQLConn -> Query -> IO OK-execute_ conn (Query qry) = command conn (COM_QUERY qry)---- | Execute a MySQL query which return a result-set with parameters.------ Note that you must fully consumed the result-set before start a new query on--- the same 'MySQLConn', or an 'UnconsumedResultSet' will be thrown.--- if you want to skip the result-set, use 'Stream.skipToEof'.----query :: QueryParam p => MySQLConn -> Query -> [p] -> IO ([ColumnDef], InputStream [MySQLValue])-query conn qry params = query_ conn (renderParams qry params)--{-# SPECIALIZE query :: MySQLConn -> Query -> [MySQLValue] -> IO ([ColumnDef], InputStream [MySQLValue]) #-}-{-# SPECIALIZE query :: MySQLConn -> Query -> [Param]      -> IO ([ColumnDef], InputStream [MySQLValue]) #-}---- | 'V.Vector' version of 'query'.------ @since 0.5.1.0----queryVector :: QueryParam p => MySQLConn -> Query -> [p] -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue))-queryVector conn qry params = queryVector_ conn (renderParams qry params)--{-# SPECIALIZE queryVector :: MySQLConn -> Query -> [MySQLValue] -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue)) #-}-{-# SPECIALIZE queryVector :: MySQLConn -> Query -> [Param]      -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue)) #-}---- | Execute a MySQL query which return a result-set.----query_ :: MySQLConn -> Query -> IO ([ColumnDef], InputStream [MySQLValue])-query_ conn@(MySQLConn is os _ consumed) (Query qry) = do-    guardUnconsumed conn-    writeCommand (COM_QUERY qry) os-    p <- readPacket is-    if isERR p-    then decodeFromPacket p >>= throwIO . ERRException-    else do-        len <- getFromPacket getLenEncInt p-        fields <- replicateM len $ (decodeFromPacket <=< readPacket) is-        _ <- readPacket is -- eof packet, we don't verify this though-        writeIORef consumed False-        rows <- Stream.makeInputStream $ do-            q <- readPacket is-            if  | isEOF q  -> writeIORef consumed True >> return Nothing-                | isERR q  -> decodeFromPacket q >>= throwIO . ERRException-                | otherwise -> Just <$> getFromPacket (getTextRow fields) q-        return (fields, rows)---- | 'V.Vector' version of 'query_'.------ @since 0.5.1.0----queryVector_ :: MySQLConn -> Query -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue))-queryVector_ conn@(MySQLConn is os _ consumed) (Query qry) = do-    guardUnconsumed conn-    writeCommand (COM_QUERY qry) os-    p <- readPacket is-    if isERR p-    then decodeFromPacket p >>= throwIO . ERRException-    else do-        len <- getFromPacket getLenEncInt p-        fields <- V.replicateM len $ (decodeFromPacket <=< readPacket) is-        _ <- readPacket is -- eof packet, we don't verify this though-        writeIORef consumed False-        rows <- Stream.makeInputStream $ do-            q <- readPacket is-            if  | isEOF q  -> writeIORef consumed True >> return Nothing-                | isERR q  -> decodeFromPacket q >>= throwIO . ERRException-                | otherwise -> Just <$> getFromPacket (getTextRowVector fields) q-        return (fields, rows)---- | Ask MySQL to prepare a query statement.----prepareStmt :: MySQLConn -> Query -> IO StmtID-prepareStmt conn@(MySQLConn is os _ _) (Query stmt) = do-    guardUnconsumed conn-    writeCommand (COM_STMT_PREPARE stmt) os-    p <- readPacket is-    if isERR p-    then decodeFromPacket p >>= throwIO . ERRException-    else do-        StmtPrepareOK stid colCnt paramCnt _ <- getFromPacket getStmtPrepareOK p-        _ <- replicateM_ paramCnt (readPacket is)-        _ <- unless (paramCnt == 0) (void (readPacket is))  -- EOF-        _ <- replicateM_ colCnt (readPacket is)-        _ <- unless (colCnt == 0) (void (readPacket is))  -- EOF-        return stid---- | Ask MySQL to prepare a query statement.------ All details from @COM_STMT_PREPARE@ Response are returned: the 'StmtPrepareOK' packet,--- params's 'ColumnDef', result's 'ColumnDef'.----prepareStmtDetail :: MySQLConn -> Query -> IO (StmtPrepareOK, [ColumnDef], [ColumnDef])-prepareStmtDetail conn@(MySQLConn is os _ _) (Query stmt) = do-    guardUnconsumed conn-    writeCommand (COM_STMT_PREPARE stmt) os-    p <- readPacket is-    if isERR p-    then decodeFromPacket p >>= throwIO . ERRException-    else do-        sOK@(StmtPrepareOK _ colCnt paramCnt _) <- getFromPacket getStmtPrepareOK p-        pdefs <- replicateM paramCnt ((decodeFromPacket <=< readPacket) is)-        _ <- unless (paramCnt == 0) (void (readPacket is))  -- EOF-        cdefs <- replicateM colCnt ((decodeFromPacket <=< readPacket) is)-        _ <- unless (colCnt == 0) (void (readPacket is))  -- EOF-        return (sOK, pdefs, cdefs)---- | Ask MySQL to closed a query statement.----closeStmt :: MySQLConn -> StmtID -> IO ()-closeStmt (MySQLConn _ os _ _) stid = do-    writeCommand (COM_STMT_CLOSE stid) os---- | Ask MySQL to reset a query statement, all previous resultset will be cleared.----resetStmt :: MySQLConn -> StmtID -> IO ()-resetStmt (MySQLConn is os _ consumed) stid = do-    writeCommand (COM_STMT_RESET stid) os  -- previous result-set may still be unconsumed-    p <- readPacket is-    if isERR p-    then decodeFromPacket p >>= throwIO . ERRException-    else writeIORef consumed True---- | Execute prepared query statement with parameters, expecting no resultset.----executeStmt :: MySQLConn -> StmtID -> [MySQLValue] -> IO OK-executeStmt conn stid params =-  command conn (COM_STMT_EXECUTE stid params (makeNullMap params))---- | Execute prepared query statement with parameters, expecting resultset.------ Rules about 'UnconsumedResultSet' applied here too.----queryStmt :: MySQLConn -> StmtID -> [MySQLValue] -> IO ([ColumnDef], InputStream [MySQLValue])-queryStmt conn@(MySQLConn is os _ consumed) stid params = do-    guardUnconsumed conn-    writeCommand (COM_STMT_EXECUTE stid params (makeNullMap params)) os-    p <- readPacket is-    if isERR p-    then decodeFromPacket p >>= throwIO . ERRException-    else do-        len <- getFromPacket getLenEncInt p-        fields <- replicateM len $ (decodeFromPacket <=< readPacket) is-        _ <- readPacket is -- eof packet, we don't verify this though-        writeIORef consumed False-        rows <- Stream.makeInputStream $ do-            q <- readPacket is-            if  | isOK  q  -> Just <$> getFromPacket (getBinaryRow fields len) q-                | isEOF q  -> writeIORef consumed True >> return Nothing-                | isERR q  -> decodeFromPacket q >>= throwIO . ERRException-                | otherwise -> throwIO (UnexpectedPacket q)-        return (fields, rows)---- | 'V.Vector' version of 'queryStmt'------ @since 0.5.1.0----queryStmtVector :: MySQLConn -> StmtID -> [MySQLValue] -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue))-queryStmtVector conn@(MySQLConn is os _ consumed) stid params = do-    guardUnconsumed conn-    writeCommand (COM_STMT_EXECUTE stid params (makeNullMap params)) os-    p <- readPacket is-    if isERR p-    then decodeFromPacket p >>= throwIO . ERRException-    else do-        len <- getFromPacket getLenEncInt p-        fields <- V.replicateM len $ (decodeFromPacket <=< readPacket) is-        _ <- readPacket is -- eof packet, we don't verify this though-        writeIORef consumed False-        rows <- Stream.makeInputStream $ do-            q <- readPacket is-            if  | isOK  q  -> Just <$> getFromPacket (getBinaryRowVector fields len) q-                | isEOF q  -> writeIORef consumed True >> return Nothing-                | isERR q  -> decodeFromPacket q >>= throwIO . ERRException-                | otherwise -> throwIO (UnexpectedPacket q)-        return (fields, rows)---- | Run querys inside a transaction, querys will be rolled back if exception arise.------ @since 0.2.0.0----withTransaction :: MySQLConn -> IO a -> IO a-withTransaction conn procedure = mask $ \restore -> do-  _ <- execute_ conn "BEGIN"-  r <- restore procedure `onException` (execute_ conn "ROLLBACK")-  _ <- execute_ conn "COMMIT"-  pure r
− Database/MySQL/BinLog.hs
@@ -1,214 +0,0 @@-{-|-Module      : Database.MySQL.BinLog-Description : Binary protocol toolkit-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--This module provide tools for binlog listening and row based binlog decoding.--}--module Database.MySQL.BinLog-    ( -- * binlog utilities-      SlaveID-    , BinLogTracker(..)-    , registerPesudoSlave-    , dumpBinLog-    , RowBinLogEvent(..)-    , decodeRowBinLogEvent-    -- * helpers-    , getLastBinLogTracker-    , isCheckSumEnabled-    , isSemiSyncEnabled-    -- * re-export-    , module Database.MySQL.BinLogProtocol.BinLogEvent-    , module Database.MySQL.BinLogProtocol.BinLogValue-    , module Database.MySQL.BinLogProtocol.BinLogMeta-    ) where--import           Control.Applicative-import           Control.Exception                         (throwIO)-import           Control.Monad-import           Data.Binary.Put-import           Data.ByteString                           (ByteString)-import           Data.IORef                                (IORef, newIORef,-                                                            readIORef,-                                                            writeIORef)-import           Data.Text.Encoding                        (encodeUtf8)-import           Data.Word-import           Database.MySQL.Base-import           Database.MySQL.BinLogProtocol.BinLogEvent-import           Database.MySQL.BinLogProtocol.BinLogMeta-import           Database.MySQL.BinLogProtocol.BinLogValue-import           Database.MySQL.Connection-import           GHC.Generics                              (Generic)-import           System.IO.Streams                         (InputStream)-import qualified System.IO.Streams                         as Stream--type SlaveID = Word32---- | binlog filename and position to start listening.----data BinLogTracker = BinLogTracker-    { btFileName :: {-# UNPACK #-} !ByteString-    , btNextPos  :: {-# UNPACK #-} !Word32-    } deriving (Show, Eq, Generic)---- | Register a pesudo slave to master, although MySQL document suggests you should call this--- before calling 'dumpBinLog', but it seems it's not really necessary.----registerPesudoSlave :: MySQLConn -> SlaveID -> IO OK-registerPesudoSlave conn sid = command conn (COM_REGISTER_SLAVE sid "" "" "" 0 0 0)---- | Setup binlog listening on given connection, during listening--- the connection CAN NOT be used to do query, or an 'UnconsumedResultSet' will be thrown.----dumpBinLog :: MySQLConn               -- ^ connection to be listened-           -> SlaveID                 -- ^ a number for our pesudo slave.-           -> BinLogTracker           -- ^ binlog position-           -> Bool                    -- ^ if master support semi-ack, do we want to enable it?-                                      -- if master doesn't support, this parameter will be ignored.-           -> IO (FormatDescription, IORef ByteString, InputStream BinLogPacket)-                -- ^ 'FormatDescription', 'IORef' contains current binlog filename, 'BinLogPacket' stream.-dumpBinLog conn@(MySQLConn is wp _ consumed) sid (BinLogTracker initfn initpos) wantAck = do-    guardUnconsumed conn-    checksum <- isCheckSumEnabled conn-    when checksum $ void $ execute_ conn "SET @master_binlog_checksum = @@global.binlog_checksum"-    semiAck  <- isSemiSyncEnabled conn-    let needAck = semiAck && wantAck-    when needAck . void $ execute_ conn "SET @rpl_semi_sync_slave = 1"-    writeCommand (COM_BINLOG_DUMP initpos 0x00 sid initfn) wp-    writeIORef consumed False--    rp <- skipToPacketT (readBinLogPacket checksum needAck is) BINLOG_ROTATE_EVENT-    re <- getFromBinLogPacket getRotateEvent rp-    fref <- newIORef (rFileName re)--    p <- skipToPacketT (readBinLogPacket checksum needAck is) BINLOG_FORMAT_DESCRIPTION_EVENT-    replyAck needAck p fref wp-    fmt <- getFromBinLogPacket getFormatDescription p--    es <- Stream.makeInputStream $ do-        q <- readBinLogPacket checksum needAck is-        case q of-            Nothing   -> writeIORef consumed True >> return Nothing-            Just q' -> do when (blEventType q' == BINLOG_ROTATE_EVENT) $ do-                                e <- getFromBinLogPacket getRotateEvent q'-                                writeIORef' fref (rFileName e)-                          replyAck needAck q' fref wp-                          return q-    return (fmt, fref, es)-  where-    skipToPacketT iop typ = do-        p <- iop-        case p of-            Just p' -> do-                if blEventType p' == typ then return p' else skipToPacketT iop typ-            Nothing -> throwIO NetworkException--    replyAck needAck p fref wp' = when (needAck && blSemiAck p) $ do-        fn <- readIORef fref-        wp' (makeSemiAckPacket (blLogPos p) fn)--    makeSemiAckPacket pos fn = putToPacket 0 $ do-        putWord8 0xEF      -- semi-ack-        putWord64le pos-        putByteString fn--    readBinLogPacket checksum needAck is' = do-        p <- readPacket is'-        if  | isOK p -> Just <$> getFromPacket (getBinLogPacket checksum needAck) p-            | isEOF p -> return Nothing-            | isERR p -> decodeFromPacket p >>= throwIO . ERRException---- | Row based binlog event type.------ It's recommended to enable row query event before 'dumpBinLog', so that you can get--- 'RowQueryEvent' in row based binlog(it's important for detect a table change for example),--- more information please refer <http://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html#sysvar_binlog_rows_query_log_events sysvar_binlog_rows_query_log_events>------ A 'BinLogTracker' is included so that you can roll up your own HA solutions,--- for example, writing the tracker to zookeeper when you done with an event.------ The first 'Word32' field is a timestamp present when this event is logged.----data RowBinLogEvent-    = RowQueryEvent  {-# UNPACK #-} !Word32 !BinLogTracker !QueryEvent'-    | RowDeleteEvent {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !DeleteRowsEvent-    | RowWriteEvent  {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !WriteRowsEvent-    | RowUpdateEvent {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !UpdateRowsEvent-  deriving (Show, Eq, Generic)---- | decode row based event from 'BinLogPacket' stream.-decodeRowBinLogEvent :: (FormatDescription, IORef ByteString, InputStream BinLogPacket)-                     -> IO (InputStream RowBinLogEvent)-decodeRowBinLogEvent (fd', fref', is') = Stream.makeInputStream (loop fd' fref' is')-  where-    loop fd fref is = do-        p <- Stream.read is-        case p of-            Nothing -> return Nothing-            Just p' -> do-                let t = blEventType p'-                if  | t == BINLOG_ROWS_QUERY_EVENT -> do-                        tr <- track p' fref-                        e <- getFromBinLogPacket getQueryEvent' p'-                        pure (Just (RowQueryEvent (blTimestamp p') tr e))-                    | t == BINLOG_TABLE_MAP_EVENT -> do-                        tme <- getFromBinLogPacket (getTableMapEvent fd) p'-                        q <- Stream.read is-                        case q of-                            Nothing -> return Nothing-                            Just q' -> do-                                let u = blEventType q'-                                if  | u == BINLOG_WRITE_ROWS_EVENTv1 || u == BINLOG_WRITE_ROWS_EVENTv2 -> do-                                        tr <- track q' fref-                                        e <- getFromBinLogPacket' (getWriteRowEvent fd tme) q'-                                        pure (Just (RowWriteEvent (blTimestamp q') tr tme e))-                                    | u == BINLOG_DELETE_ROWS_EVENTv1 || u == BINLOG_DELETE_ROWS_EVENTv2 -> do-                                        tr <- track q' fref-                                        e <- getFromBinLogPacket' (getDeleteRowEvent fd tme) q'-                                        pure (Just (RowDeleteEvent (blTimestamp q') tr tme e))-                                    | u == BINLOG_UPDATE_ROWS_EVENTv1 || u == BINLOG_UPDATE_ROWS_EVENTv2 -> do-                                        tr <- track q' fref-                                        e <- getFromBinLogPacket' (getUpdateRowEvent fd tme) q'-                                        pure (Just (RowUpdateEvent (blTimestamp q') tr tme e))-                                    | otherwise -> loop fd fref is-                    | otherwise -> loop fd fref is--    track p fref = BinLogTracker <$> readIORef fref <*> (pure . fromIntegral . blLogPos) p---- | Get latest master's binlog filename and position.----getLastBinLogTracker :: MySQLConn -> IO (Maybe BinLogTracker)-getLastBinLogTracker conn = do-    (_, is) <- query_ conn "SHOW MASTER STATUS"-    row <- Stream.read is-    Stream.skipToEof is-    case row of-        Just (MySQLText fn : MySQLInt64U pos : _) -> return . Just $ BinLogTracker (encodeUtf8 fn) (fromIntegral pos)-        _                                         -> return Nothing---- | Return True if binlog_checksum = CRC32. Only for MySQL > 5.6----isCheckSumEnabled :: MySQLConn -> IO Bool-isCheckSumEnabled conn = do-    (_, is) <- query_ conn "SHOW GLOBAL VARIABLES LIKE 'binlog_checksum'"-    row <- Stream.read is-    Stream.skipToEof is-    case row of-        Just [_, MySQLText "CRC32"] -> return True-        _                           -> return False---- | Return True if rpl_semi_sync_master_enabled = ON. Only for MySQL > 5.5----isSemiSyncEnabled :: MySQLConn -> IO Bool-isSemiSyncEnabled conn = do-    (_, is) <- query_ conn "SHOW VARIABLES LIKE 'rpl_semi_sync_master_enabled'"-    row <- Stream.read is-    Stream.skipToEof is-    case row of-        Just [_, MySQLText "ON"] -> return True-        _                        -> return False
− Database/MySQL/BinLogProtocol/BinLogEvent.hs
@@ -1,291 +0,0 @@-{-# OPTIONS_GHC -funbox-strict-fields #-}--{-|-Module      : Database.MySQL.BinLogProtocol.BinLogEvent-Description : Binlog event-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--Binlog event type--}--module Database.MySQL.BinLogProtocol.BinLogEvent where--import           Control.Applicative-import           Control.Monad-import           Control.Monad.Loops                       (untilM)-import           Data.Binary-import           Data.Binary.Parser-import           Data.Bits-import           Data.ByteString                           (ByteString)-import qualified Data.ByteString                           as B-import qualified Data.ByteString.Lazy                      as L-import qualified Data.ByteString.Unsafe                    as B-import           Database.MySQL.BinLogProtocol.BinLogMeta-import           Database.MySQL.BinLogProtocol.BinLogValue-import           Database.MySQL.Protocol.Packet-import           Database.MySQL.Protocol.MySQLValue-import           Database.MySQL.Protocol.ColumnDef--import           Control.Exception                         (throwIO)-import           Database.MySQL.Query-import           GHC.Generics                              (Generic)------------------------------------------------------------------------------------- | binlog tyoe----data BinLogEventType-    = BINLOG_UNKNOWN_EVENT-    | BINLOG_START_EVENT_V3-    | BINLOG_QUERY_EVENT-    | BINLOG_STOP_EVENT-    | BINLOG_ROTATE_EVENT-    | BINLOG_INTVAR_EVENT-    | BINLOG_LOAD_EVENT-    | BINLOG_SLAVE_EVENT-    | BINLOG_CREATE_FILE_EVENT-    | BINLOG_APPEND_BLOCK_EVENT-    | BINLOG_EXEC_LOAD_EVENT-    | BINLOG_DELETE_FILE_EVENT-    | BINLOG_NEW_LOAD_EVENT-    | BINLOG_RAND_EVENT-    | BINLOG_USER_VAR_EVENT-    | BINLOG_FORMAT_DESCRIPTION_EVENT-    | BINLOG_XID_EVENT-    | BINLOG_BEGIN_LOAD_QUERY_EVENT-    | BINLOG_EXECUTE_LOAD_QUERY_EVENT-    | BINLOG_TABLE_MAP_EVENT-    | BINLOG_WRITE_ROWS_EVENTv0-    | BINLOG_UPDATE_ROWS_EVENTv0-    | BINLOG_DELETE_ROWS_EVENTv0-    | BINLOG_WRITE_ROWS_EVENTv1-    | BINLOG_UPDATE_ROWS_EVENTv1-    | BINLOG_DELETE_ROWS_EVENTv1-    | BINLOG_INCIDENT_EVENT-    | BINLOG_HEARTBEAT_EVENT-    | BINLOG_IGNORABLE_EVENT-    | BINLOG_ROWS_QUERY_EVENT-    | BINLOG_WRITE_ROWS_EVENTv2-    | BINLOG_UPDATE_ROWS_EVENTv2-    | BINLOG_DELETE_ROWS_EVENTv2-    | BINLOG_GTID_EVENT-    | BINLOG_ANONYMOUS_GTID_EVENT-    | BINLOG_PREVIOUS_GTIDS_EVENT-  deriving (Show, Eq, Enum)--data BinLogPacket = BinLogPacket-    { blTimestamp :: !Word32-    , blEventType :: !BinLogEventType-    , blServerId  :: !Word32-    , blEventSize :: !Word32-    , blLogPos    :: !Word64   -- ^ for future GTID compatibility-    , blFlags     :: !Word16-    , blBody      :: !L.ByteString-    , blSemiAck   :: !Bool-    } deriving (Show, Eq)--putSemiAckResp :: Word32 -> ByteString -> Put-putSemiAckResp pos fn = put pos >> put fn--getBinLogPacket :: Bool -> Bool -> Get BinLogPacket-getBinLogPacket checksum semi = do-    _  <- getWord8     -- OK byte-    ack <- if semi-        then getWord8 >> (== 0x01) <$> getWord8-        else return False-    ts <- getWord32le-    typ <- toEnum . fromIntegral <$> getWord8-    sid <- getWord32le-    size <- getWord32le-    pos <- getWord32le-    flgs <- getWord16le-    body <- getLazyByteString (fromIntegral size - if checksum then 23 else 19)-    return (BinLogPacket ts typ sid size (fromIntegral pos) flgs body ack)--getFromBinLogPacket :: Get a -> BinLogPacket -> IO a-getFromBinLogPacket g (BinLogPacket _ _ _ _ _ _ body _ ) =-    case parseDetailLazy g body  of-        Left  (buf, offset, errmsg) -> throwIO (DecodePacketFailed buf offset errmsg)-        Right (_,   _,      r     ) -> return r--getFromBinLogPacket' :: (BinLogEventType -> Get a) -> BinLogPacket -> IO a-getFromBinLogPacket' g (BinLogPacket _ typ _ _ _ _ body _ ) =-    case parseDetailLazy (g typ) body  of-        Left  (buf, offset, errmsg) -> throwIO (DecodePacketFailed buf offset errmsg)-        Right (_,   _,      r     ) -> return r------------------------------------------------------------------------------------data FormatDescription = FormatDescription-    { fdVersion              :: !Word16-    , fdMySQLVersion         :: !ByteString-    , fdCreateTime           :: !Word32-    -- , eventHeaderLen :: !Word8  -- const 19-    , fdEventHeaderLenVector :: !ByteString  -- ^ a array indexed by Binlog Event Type - 1-                                             -- to extract the length of the event specific header.-    } deriving (Show, Eq, Generic)--getFormatDescription :: Get FormatDescription-getFormatDescription = FormatDescription <$> getWord16le-                                         <*> getByteString 50-                                         <*> getWord32le-                                         <*  getWord8-                                         <*> (L.toStrict <$> getRemainingLazyByteString)--eventHeaderLen :: FormatDescription -> BinLogEventType -> Word8-eventHeaderLen fd typ = B.unsafeIndex (fdEventHeaderLenVector fd) (fromEnum typ - 1)--data RotateEvent = RotateEvent-    { rPos :: !Word64, rFileName :: !ByteString } deriving (Show, Eq)--getRotateEvent :: Get RotateEvent-getRotateEvent = RotateEvent <$> getWord64le <*> getRemainingByteString---- | This's query parser for statement based binlog's query event, it's actually--- not used in row based binlog.----data QueryEvent = QueryEvent-    { qSlaveProxyId :: !Word32-    , qExecTime     :: !Word32-    , qErrCode      :: !Word16-    , qStatusVars   :: !ByteString-    , qSchemaName   :: !ByteString-    , qQuery        :: !Query-    } deriving (Show, Eq, Generic)--getQueryEvent :: Get QueryEvent-getQueryEvent = do-    pid <- getWord32le-    tim <- getWord32le-    slen <- getWord8-    ecode <- getWord16le-    vlen <- getWord16le-    svar <- getByteString (fromIntegral vlen)-    schema <- getByteString (fromIntegral slen)-    _ <- getWord8-    qry <- getRemainingLazyByteString-    return (QueryEvent pid tim ecode svar schema (Query qry))---- | This's the query event in row based binlog.----data QueryEvent' = QueryEvent' { qQuery' :: !Query } deriving (Show, Eq)--getQueryEvent' :: Get QueryEvent'-getQueryEvent' = do-    _ <- getWord8-    QueryEvent' . Query <$> getRemainingLazyByteString--data TableMapEvent = TableMapEvent-    { tmTableId    :: !Word64-    , tmFlags      :: !Word16-    , tmSchemaName :: !ByteString-    , tmTableName  :: !ByteString-    , tmColumnCnt  :: !Int-    , tmColumnType :: ![FieldType]-    , tmColumnMeta :: ![BinLogMeta]-    , tmNullMap    :: !ByteString-    } deriving (Show, Eq, Generic)--getTableMapEvent :: FormatDescription -> Get TableMapEvent-getTableMapEvent fd = do-    let hlen = eventHeaderLen fd BINLOG_TABLE_MAP_EVENT-    tid <- if hlen == 6 then fromIntegral <$> getWord32le else getWord48le-    flgs <- getWord16le-    slen <- getWord8-    schema <- getByteString (fromIntegral slen)-    _ <- getWord8 -- 0x00-    tlen <- getWord8-    table <- getByteString (fromIntegral tlen)-    _ <- getWord8 -- 0x00-    cc <- getLenEncInt-    colTypBS <- getByteString cc-    let typs = map FieldType (B.unpack colTypBS)-    colMetaBS <- getLenEncBytes--    metas <- case runGetOrFail (forM typs getBinLogMeta) (L.fromStrict colMetaBS) of-        Left (_, _, errmsg) -> fail errmsg-        Right (_, _, r)     -> return r--    nullmap <- getByteString ((cc + 7) `div` 8)-    return (TableMapEvent tid flgs schema table cc typs metas nullmap)--data DeleteRowsEvent = DeleteRowsEvent-    { deleteTableId    :: !Word64-    , deleteFlags      :: !Word16-    -- , deleteExtraData   :: !RowsEventExtraData-    , deleteColumnCnt  :: !Int-    , deletePresentMap :: !BitMap-    , deleteRowData    :: ![[BinLogValue]]-    } deriving (Show, Eq, Generic)--getDeleteRowEvent :: FormatDescription -> TableMapEvent -> BinLogEventType -> Get DeleteRowsEvent-getDeleteRowEvent fd tme typ = do-    let hlen = eventHeaderLen fd typ-    tid <- if hlen == 6 then fromIntegral <$> getWord32le else getWord48le-    flgs <- getWord16le-    when (typ == BINLOG_DELETE_ROWS_EVENTv2) $ do-        extraLen <- getWord16le-        void $ getByteString (fromIntegral extraLen - 2)-    colCnt <- getLenEncInt-    let (plen, poffset) = (fromIntegral colCnt + 7) `quotRem` 8-    pmap <- getPresentMap plen poffset-    DeleteRowsEvent tid flgs colCnt pmap <$> untilM (getBinLogRow (tmColumnMeta tme) pmap) isEmpty--data WriteRowsEvent = WriteRowsEvent-    { writeTableId    :: !Word64-    , writeFlags      :: !Word16-    -- , writeExtraData   :: !RowsEventExtraData-    , writeColumnCnt  :: !Int-    , writePresentMap :: !BitMap-    , writeRowData    :: ![[BinLogValue]]-    } deriving (Show, Eq, Generic)--getWriteRowEvent :: FormatDescription -> TableMapEvent -> BinLogEventType -> Get WriteRowsEvent-getWriteRowEvent fd tme typ = do-    let hlen = eventHeaderLen fd typ-    tid <- if hlen == 6 then fromIntegral <$> getWord32le else getWord48le-    flgs <- getWord16le-    when (typ == BINLOG_WRITE_ROWS_EVENTv2) $ do-        extraLen <- getWord16le-        void $ getByteString (fromIntegral extraLen - 2)-    colCnt <- getLenEncInt-    let (plen, poffset) = (fromIntegral colCnt + 7) `quotRem` 8-    pmap <- getPresentMap plen poffset-    WriteRowsEvent tid flgs colCnt pmap <$> untilM (getBinLogRow (tmColumnMeta tme) pmap) isEmpty--data UpdateRowsEvent = UpdateRowsEvent-    { updateTableId    :: !Word64-    , updateFlags      :: !Word16-    -- , updateExtraData   :: !RowsEventExtraData-    , updateColumnCnt  :: !Int-    , updatePresentMap :: !(BitMap, BitMap)-    , updateRowData    :: ![ ([BinLogValue], [BinLogValue]) ]-    } deriving (Show, Eq, Generic)--getUpdateRowEvent :: FormatDescription -> TableMapEvent -> BinLogEventType -> Get UpdateRowsEvent-getUpdateRowEvent fd tme typ = do-    let hlen = eventHeaderLen fd typ-    tid <- if hlen == 6 then fromIntegral <$> getWord32le else getWord48le-    flgs <- getWord16le-    when (typ == BINLOG_UPDATE_ROWS_EVENTv2) $ do-        extraLen <- getWord16le-        void $ getByteString (fromIntegral extraLen - 2)-    colCnt <- getLenEncInt-    let (plen, poffset) = (fromIntegral colCnt + 7) `quotRem` 8-    pmap <- getPresentMap plen poffset-    pmap' <- getPresentMap plen poffset-    UpdateRowsEvent tid flgs colCnt (pmap, pmap') <$>-        untilM ((,) <$> getBinLogRow (tmColumnMeta tme) pmap <*> getBinLogRow (tmColumnMeta tme) pmap')-               isEmpty--getPresentMap :: Int -> Int -> Get BitMap-getPresentMap plen poffset = do-    pmap <- getByteString plen-    let pmap' = if B.null pmap-                then B.empty-                else B.init pmap `B.snoc` (B.last pmap .&. 0xFF `shiftR` (7 - poffset))-    pure (BitMap pmap')-
− Database/MySQL/BinLogProtocol/BinLogMeta.hs
@@ -1,120 +0,0 @@-{-# OPTIONS_GHC -funbox-strict-fields #-}--{-|-Module      : Database.MySQL.BinLogProtocol.BinLogMeta-Description : Binlog protocol column meta-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--This module provide column meta decoder for binlog protocol.--There're certain type won't appear in binlog event, and some types are compressed into 'mySQLTypeString'-, please take python version as a reference:  <https://github.com/noplay/python-mysql-replication>--You will not directly meet following 'FieldType' namely:--    * mySQLTypeDecimal-    * mySQLTypeNewdate-    * mySQLTypeEnum-    * mySQLTypeSet-    * mySQLTypeTinyBlob-    * mySQLTypeMediumBlOb-    * mySQLTypeLongBlob---}--module Database.MySQL.BinLogProtocol.BinLogMeta where--import           Control.Applicative-import           Data.Binary.Get-import           Data.Bits-import           Data.Word-import           Database.MySQL.Protocol.ColumnDef---- | An intermedia date type for decoding row-based event's values.----data BinLogMeta-    = BINLOG_TYPE_TINY-    | BINLOG_TYPE_SHORT-    | BINLOG_TYPE_INT24-    | BINLOG_TYPE_LONG-    | BINLOG_TYPE_LONGLONG-    | BINLOG_TYPE_FLOAT       !Word8         -- ^ size-    | BINLOG_TYPE_DOUBLE      !Word8         -- ^ size-    | BINLOG_TYPE_BIT         !Word16 !Word8 -- ^ bits, bytes-    | BINLOG_TYPE_TIMESTAMP-    | BINLOG_TYPE_DATETIME-    | BINLOG_TYPE_DATE-    | BINLOG_TYPE_TIME-    | BINLOG_TYPE_TIMESTAMP2  !Word8         -- ^ fsp-    | BINLOG_TYPE_DATETIME2   !Word8         -- ^ fsp-    | BINLOG_TYPE_TIME2       !Word8         -- ^ fsp-    | BINLOG_TYPE_YEAR-    | BINLOG_TYPE_NEWDECIMAL  !Word8 !Word8  -- ^ precision, scale-    | BINLOG_TYPE_ENUM        !Word8         -- ^ 1 or 2('Word8' or 'Word16'), enum index size-    | BINLOG_TYPE_SET         !Word16 !Word8 -- ^ bitmap bits, bytes-    | BINLOG_TYPE_BLOB        !Word8         -- ^ length size-    | BINLOG_TYPE_STRING      !Word16        -- ^ meta length(if < 256, then length is 8bit,-                                             -- if > 256 then length is 16bit)-    | BINLOG_TYPE_GEOMETRY    !Word8         -- ^ length size-  deriving (Show, Eq)--getBinLogMeta :: FieldType -> Get BinLogMeta-getBinLogMeta t-    | t == mySQLTypeTiny       = pure BINLOG_TYPE_TINY-    | t == mySQLTypeShort      = pure BINLOG_TYPE_SHORT-    | t == mySQLTypeInt24      = pure BINLOG_TYPE_INT24-    | t == mySQLTypeLong       = pure BINLOG_TYPE_LONG-    | t == mySQLTypeLongLong   = pure BINLOG_TYPE_LONGLONG-    | t == mySQLTypeFloat      = BINLOG_TYPE_FLOAT <$> getWord8-    | t == mySQLTypeDouble     = BINLOG_TYPE_DOUBLE <$> getWord8--    | t == mySQLTypeBit        = do-        byte0 <- getWord8-        byte1 <- getWord8-        let nbits = (fromIntegral byte1 `shiftL` 3) .|.  fromIntegral byte0-            nbytes = fromIntegral $ (nbits + 7) `shiftR` 3-        pure (BINLOG_TYPE_BIT nbits nbytes)--    | t == mySQLTypeTimestamp  = pure BINLOG_TYPE_TIMESTAMP-    | t == mySQLTypeDateTime   = pure BINLOG_TYPE_DATETIME-    | t == mySQLTypeDate       = pure BINLOG_TYPE_DATE-    | t == mySQLTypeTime       = pure BINLOG_TYPE_TIME-    | t == mySQLTypeTimestamp2 = BINLOG_TYPE_TIMESTAMP2 <$> getWord8-    | t == mySQLTypeDateTime2  = BINLOG_TYPE_DATETIME2 <$> getWord8-    | t == mySQLTypeTime2      = BINLOG_TYPE_TIME2 <$> getWord8-    | t == mySQLTypeYear       = pure BINLOG_TYPE_YEAR-    | t == mySQLTypeNewDecimal = BINLOG_TYPE_NEWDECIMAL <$> getWord8 <*> getWord8-    | t == mySQLTypeVarChar    = BINLOG_TYPE_STRING <$> getWord16le-    | t == mySQLTypeVarString  = BINLOG_TYPE_STRING <$> getWord16le--    | t == mySQLTypeString     = do-        byte0 <- getWord8-        byte1 <- getWord8-        -- http://bugs.mysql.com/37426-        if  byte0 > 0-        then if (byte0 .&. 0x30) /= 0x30-             then if FieldType (byte0 .|. 0x30) == mySQLTypeString-                  then let len = fromIntegral $ (byte0 .&. 0x30) `xor` 0x30-                           len' = len `shiftL` 4 .|. fromIntegral byte1-                       in pure $! BINLOG_TYPE_STRING len'-                  else let len = fromIntegral byte0 `shiftL` 8 :: Word16-                           len' = len .|. fromIntegral byte1-                       in pure $! BINLOG_TYPE_STRING len'-             else let t' = FieldType byte0-                  in if | t' == mySQLTypeSet    -> let nbits = fromIntegral byte1 `shiftL` 3-                                                       nbytes = fromIntegral $ (nbits + 7) `shiftR` 8-                                                   in pure (BINLOG_TYPE_SET nbits nbytes)-                        | t' == mySQLTypeEnum   -> pure (BINLOG_TYPE_ENUM byte1)-                        | t' == mySQLTypeString -> pure (BINLOG_TYPE_STRING (fromIntegral byte1))-                        | otherwise             -> fail $ "Database.MySQL.BinLogProtocol.BinLogMeta:\-                                                           \ impossible type inside binlog string: " ++ show t'-        else pure (BINLOG_TYPE_STRING (fromIntegral byte1))--    | t == mySQLTypeBlob       = BINLOG_TYPE_BLOB <$> getWord8-    | t == mySQLTypeGeometry   = BINLOG_TYPE_GEOMETRY <$> getWord8-    | otherwise                = fail $ "Database.MySQL.BinLogProtocol.BinLogMeta:\-                                        \ impossible type in binlog: " ++ show t
− Database/MySQL/BinLogProtocol/BinLogValue.hs
@@ -1,325 +0,0 @@-{-|-Module      : Database.MySQL.BinLogProtocol.BinLogValue-Description : Binlog protocol-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--Binlog protocol---}--module Database.MySQL.BinLogProtocol.BinLogValue where--import           Control.Applicative-import           Data.Binary.Get-import           Data.Binary.IEEE754-import           Data.Binary.Put                          ()-import           Data.Bits-import           Data.ByteString                          (ByteString)-import qualified Data.ByteString                          as B-import qualified Data.ByteString.Unsafe                   as B-import           Data.Int-import           Data.Int.Int24-import           Data.Scientific-import           Data.Word-import           Database.MySQL.BinLogProtocol.BinLogMeta-import           Database.MySQL.Protocol.MySQLValue-import           Database.MySQL.Protocol.Packet-import           GHC.Generics                             (Generic)---- | Data type for representing binlog values.------ This data type DOES NOT try to parse binlog values into detailed haskell values,--- because you may not want to waste performance in situations like database middleware.------ Due to the lack of signedness infomation in binlog meta, we cannot distinguish,--- for example, between unsigned tiny 255 and tiny -1, so we use int to present--- @TINY,SHORT,INT,LONG@. If you have unsigned columns, use 'fromIntegral' to convert it--- to word to get real unsigned value back, for example, @fromIntegral (-1 :: Int) == 255 :: Word@------ For above reason, we use 'Int24' to present MySQL's @INT24@ type, you can get back the--- unsigned value using @word24@ package's 'Word24' type.------ Timestamp types('BinLogTimeStamp' and 'BinLogTimeStamp2') are values converted into UTC already,--- see 'MySQLVaule' 's note.------ There's also no infomation about charset, so we use 'ByteString' to present both text--- and blob types, if you want to get text representation back, you have to query column charset--- infomation, and use icu or iconv to decode. IT MAY NOT BE UTF-8.------ The @SET@ and @ENUM@ values are presented by their index's value and bitmap respectively,--- if you need get the string value back, you have to perform a 'DESC tablename' to get the--- set or enum table.----data BinLogValue-    = BinLogTiny       !Int8-    | BinLogShort      !Int16-    | BinLogInt24      !Int24-    | BinLogLong       !Int32-    | BinLogLongLong   !Int64-    | BinLogFloat      !Float-    | BinLogDouble     !Double-    | BinLogBit        !Word64          -- ^ a 64bit bitmap.-    | BinLogTimeStamp  !Word32          -- ^ a utc timestamp, note 0 doesn't mean @1970-01-01 00:00:00@,-                                        -- because mysql choose 0 to present '0000-00-00 00:00:00'-    | BinLogTimeStamp2 !Word32 !Word32  -- ^ like 'BinLogTimeStamp' with an addtional microseconds field.-    | BinLogDateTime   !Word16 !Word8 !Word8 !Word8 !Word8 !Word8         -- ^ YYYY MM DD hh mm ss-    | BinLogDateTime2  !Word16 !Word8 !Word8 !Word8 !Word8 !Word8 !Word32 -- ^ YYYY MM DD hh mm ss microsecond-    | BinLogDate       !Word16 !Word8 !Word8                   -- ^ YYYY MM DD-    | BinLogTime       !Word8  !Word16 !Word8 !Word8           -- ^ sign(1= non-negative, 0= negative) hh mm ss-    | BinLogTime2      !Word8  !Word16 !Word8 !Word8 !Word32   -- ^ sign(1= non-negative, 0= negative) hh mm ss microsecond-    | BinLogYear       !Word16                                 -- ^ year value, 0 stand for '0000'-    | BinLogNewDecimal !Scientific                             -- ^ sign(1= non-negative, 0= negative) integeral part, fractional part-    | BinLogEnum       !Word16                                 -- ^ enum indexing value-    | BinLogSet        !Word64                                 -- ^ set indexing 64bit bitmap.-    | BinLogBytes      !ByteString                             -- ^ all string and blob values.-    | BinLogGeometry   !ByteString-    | BinLogNull-  deriving (Show, Eq, Generic)------------------------------------------------------------------------------------- | BinLog protocol decoder----getBinLogField :: BinLogMeta -> Get BinLogValue-getBinLogField BINLOG_TYPE_TINY                = BinLogTiny     <$> getInt8-getBinLogField BINLOG_TYPE_SHORT               = BinLogShort    <$> getInt16le-getBinLogField BINLOG_TYPE_INT24               = BinLogInt24 . fromIntegral <$> getWord24le-getBinLogField BINLOG_TYPE_LONG                = BinLogLong     <$> getInt32le-getBinLogField BINLOG_TYPE_LONGLONG            = BinLogLongLong <$> getInt64le-getBinLogField (BINLOG_TYPE_FLOAT  _         ) = BinLogFloat <$> getFloatle-getBinLogField (BINLOG_TYPE_DOUBLE _         ) = BinLogDouble <$> getDoublele-getBinLogField (BINLOG_TYPE_BIT    _    bytes) = BinLogBit <$> getBits' bytes-getBinLogField BINLOG_TYPE_TIMESTAMP           = BinLogTimeStamp <$> getWord32le---- A integer in @YYYYMMDD@ format, for example:--- 99991231 stand for @9999-12-31@-getBinLogField BINLOG_TYPE_DATE = do-    i <- getWord24le-    let (i', dd) = i `quotRem` 32-        (yyyy, mm) = i' `quotRem` 16-    pure (BinLogDate (fromIntegral yyyy)-                     (fromIntegral mm)-                     (fromIntegral dd))--getBinLogField (BINLOG_TYPE_TIMESTAMP2  fsp) = do-    s <- getWord32be -- big-endian here!-    ms <- fromIntegral <$> getMicroSecond fsp-    pure (BinLogTimeStamp2 s ms)---- A integer in @YYYYMMDDhhmmss@, for example:--- 99991231235959 stand for @9999-12-31 23:59:59@-getBinLogField BINLOG_TYPE_DATETIME = do-    i <- getWord64le-    let (yyyy, i')   = i      `quotRem` 10000000000-        (mm, i'')    = i'     `quotRem` 100000000-        (dd, i''')   = i''    `quotRem` 1000000-        (h, i'''')   = i'''   `quotRem` 10000-        (m, s)       = i''''  `quotRem` 100-    pure (BinLogDateTime (fromIntegral yyyy)-                         (fromIntegral mm)-                         (fromIntegral dd)-                         (fromIntegral h)-                         (fromIntegral m)-                         (fromIntegral s))---- BINLOG_TYPE_DATETIME2(big endian)------ 1 bit sign (used when on disk)--- 17 bits year * 13 + month (year 0-9999, month 0-12)--- 5 bits day (0-31)--- 5 bits hour (0-23)--- 6 bits minute (0-59)--- 6 bits second (0-59)--- (5 bytes in total)------ fractional-seconds storage (size depends on meta)----getBinLogField (BINLOG_TYPE_DATETIME2 fsp) = do-    iPart <- getWord40be-    let yyyymm = iPart `shiftR` 22 .&. 0x01FFFF -- 0b011111111111111111-        (yyyy, mm) = yyyymm `quotRem` 13-        yyyy' = fromIntegral yyyy-        mm' = fromIntegral mm-        dd = fromIntegral $ iPart `shiftR` 17 .&. 0x1F -- 0b00011111-        h =  fromIntegral $ iPart `shiftR` 12 .&. 0x1F -- 0b00011111-        m =  fromIntegral $ iPart `shiftR` 6 .&. 0x3F  -- 0b00111111-        s =  fromIntegral $ iPart .&. 0x3F             -- 0b00111111-    ms <- fromIntegral <$> getMicroSecond fsp-    pure (BinLogDateTime2 yyyy' mm' dd h m s ms)---- A integer in @hhmmss@ format(can be negative), for example:--- 8385959 stand for @838:59:59@-getBinLogField BINLOG_TYPE_TIME = do-    i <- getWord24le-    let i' =  fromIntegral i :: Int24-        sign = if i' >= 0 then 1 else 0-    let (h, i'')     = i'     `quotRem` 10000-        (m, s)       = i''    `quotRem` 100-    pure (BinLogTime sign (fromIntegral (abs h))-                          (fromIntegral (abs m))-                          (fromIntegral (abs s)))---- BINLOG_TYPE_TIME2(big endian)------ 1 bit sign  (1= non-negative, 0= negative)--- 1 bit unused (Reserved for wider hour range, e.g. for intervals)--- 10 bit hour (0-836)--- 6 bit minute (0-59)--- 6 bit second (0-59)--- (3 bytes in total)------ fractional-seconds storage (size depends on meta)----getBinLogField (BINLOG_TYPE_TIME2 fsp) = do-    iPart <- getWord24be-    let sign = fromIntegral $ iPart `shiftR` 23-        iPart' = if sign == 0 then 0x800000 - iPart - 1 else iPart-        h = fromIntegral (iPart' `shiftR` 12) .&. 0x03FF -- 0b0000001111111111-        m = fromIntegral (iPart' `shiftR` 6) .&. 0x3F    -- 0b00111111-        s = fromIntegral iPart' .&. 0x3F               -- 0b00111111-    ms <- abs <$> getMicroSecond fsp-    let ms' = abs (fromIntegral ms :: Int)-    pure (BinLogTime2 sign h m s (fromIntegral ms'))--getBinLogField BINLOG_TYPE_YEAR                = do-    y <- getWord8-    pure $! if y == 0 then BinLogYear 0 else BinLogYear (1900 + fromIntegral y)---- Decimal representation in binlog seems to be as follows:------ 1st bit - sign such that set == +, unset == ---- every 4 bytes represent 9 digits in big-endian order.------ 80 00 00 05 1b 38 b0 60 00 means:------   0x80 - positive---   0x00000005 - 5---   0x1b38b060 - 456700000---   0x00       - 0------ 54567000000 / 10^{10} = 5.4567------ if there're < 9 digits at first, it will be compressed into suitable length words--- following a simple lookup table.----getBinLogField (BINLOG_TYPE_NEWDECIMAL precision scale) = do-    let i = fromIntegral (precision - scale)-        (ucI, cI) = i `quotRem` digitsPerInteger-        (ucF, cF) = scale `quotRem` digitsPerInteger-        ucISize = fromIntegral (ucI `shiftL` 2)-        ucFSize = fromIntegral (ucF `shiftL` 2)-        cISize = fromIntegral (sizeTable `B.unsafeIndex` fromIntegral cI)-        cFSize = fromIntegral (sizeTable `B.unsafeIndex` fromIntegral cF)-        len = ucISize + cISize + ucFSize + cFSize--    buf <- getByteString (fromIntegral len)--    let fb = buf `B.unsafeIndex` 0-        sign = if fb .&. 0x80 == 0x80 then 1 else 0 :: Word8-        buf' = (fb `xor` 0x80) `B.cons` B.tail buf-        buf'' = if sign == 1 then buf'-                            else B.map (xor 0xFF) buf'--        iPart = fromIntegral (getCompressed cISize (B.unsafeTake cISize buf'')) * (blockSize ^ ucI)-              + getUncompressed ucI (B.unsafeDrop cISize buf'')--    let buf''' = B.unsafeDrop (ucISize + cISize) buf''--        fPart = getUncompressed ucF (B.unsafeTake ucFSize buf''') * (10 ^ cF)-              + fromIntegral (getCompressed cFSize (B.unsafeDrop ucFSize buf'''))--    let sci = scientific (iPart * 10 ^ scale + fPart) (negate $ fromIntegral scale)-        sci' = if sign == 0 then negate sci else sci-    pure (BinLogNewDecimal sci')-  where-    digitsPerInteger = 9-    blockSize = fromIntegral $ (10 :: Int32) ^ (9 :: Int)-    sizeTable = B.pack [0, 1, 1, 2, 2, 3, 3, 4, 4, 4]--    getCompressed :: Int -> ByteString -> Word64-    getCompressed 0 _  = 0-    getCompressed x bs = let fb = bs `B.unsafeIndex` 0-                             x' = x - 1-                         in fromIntegral fb `shiftL` (8 * x') .|. getCompressed x' (B.unsafeDrop 1 bs)--    getUncompressed :: Word8 -> ByteString -> Integer-    getUncompressed 0 _ = 0-    getUncompressed x bs = let v = getCompressed 4 (B.unsafeTake 4 bs)-                               x' = x - 1-                           in fromIntegral v * (blockSize ^ x') + getUncompressed x' (B.unsafeDrop 4 bs)---getBinLogField (BINLOG_TYPE_ENUM size) =-    if  | size == 1 -> BinLogEnum . fromIntegral <$> getWord8-        | size == 2 -> BinLogEnum . fromIntegral <$> getWord16be-        | otherwise -> fail $ "Database.MySQL.BinLogProtocol.BinLogValue: wrong \-                              \BINLOG_TYPE_ENUM size: " ++ show size---getBinLogField (BINLOG_TYPE_SET _ bytes) = BinLogSet <$> getBits' bytes-getBinLogField (BINLOG_TYPE_BLOB lensize) = do-    len <- if  | lensize == 1 -> fromIntegral <$> getWord8-               | lensize == 2 -> fromIntegral <$> getWord16le-               | lensize == 3 -> fromIntegral <$> getWord24le-               | lensize == 4 -> fromIntegral <$> getWord32le-               | otherwise    -> fail $ "Database.MySQL.BinLogProtocol.BinLogValue: \-                                        \wrong BINLOG_TYPE_BLOB length size: " ++ show lensize-    BinLogBytes <$> getByteString len--getBinLogField (BINLOG_TYPE_STRING size) = do-    len <- if | size < 256 -> fromIntegral <$> getWord8-              | otherwise  -> fromIntegral <$> getWord16le-    BinLogBytes <$> getByteString len--getBinLogField (BINLOG_TYPE_GEOMETRY lensize) = do-    len <- if | lensize == 1 -> fromIntegral <$> getWord8-              | lensize == 2 -> fromIntegral <$> getWord16le-              | lensize == 3 -> fromIntegral <$> getWord24le-              | lensize == 4 -> fromIntegral <$> getWord32le-              | otherwise    -> fail $  "Database.MySQL.BinLogProtocol.BinLogValue: \-                                        \wrong BINLOG_TYPE_GEOMETRY length size: " ++ show lensize-    BinLogGeometry <$> getByteString len--getMicroSecond :: Word8 -> Get Int32-getMicroSecond 0 = pure 0-getMicroSecond 1 = (* 100000) . fromIntegral <$> getInt8-getMicroSecond 2 = (* 10000) . fromIntegral <$> getInt8-getMicroSecond 3 = (* 1000) . fromIntegral <$> getInt16be-getMicroSecond 4 = (* 100) . fromIntegral <$> getInt16be-getMicroSecond 5 = (* 10) . fromIntegral <$> getInt24be-getMicroSecond 6 = fromIntegral <$> getInt24be-getMicroSecond _ = pure 0--getBits' :: Word8 -> Get Word64-getBits' bytes = if bytes <= 8-    then getBits (fromIntegral bytes)-    else fail $  "Database.MySQL.BinLogProtocol.BinLogValue: \-                 \wrong bit length size: " ++ show bytes------------------------------------------------------------------------------------- | BinLog row decoder----getBinLogRow :: [BinLogMeta] -> BitMap -> Get [BinLogValue]-getBinLogRow metas pmap = do-    let plen = B.foldl' (\acc word8 -> acc + popCount word8) 0 (fromBitMap pmap)-        maplen = (plen + 7) `shiftR` 3-    nullmap <- getByteString maplen-    go metas (BitMap nullmap) 0 pmap 0-  where-    go :: [BinLogMeta] -> BitMap -> Int -> BitMap -> Int -> Get [BinLogValue]-    go []     _       _       _     _    = pure []-    go (f:fs) nullmap nullpos pmap' ppos = do-        let ppos' = ppos + 1-        if isColumnSet pmap' ppos-        then do-            r <- if isColumnSet nullmap nullpos-                    then return BinLogNull-                    else getBinLogField f-            let nullpos' = nullpos + 1-            rest <- nullpos' `seq` ppos' `seq` go fs nullmap nullpos' pmap' ppos'-            return (rest `seq` (r : rest))-        else ppos' `seq` go fs nullmap nullpos pmap' ppos'-
− Database/MySQL/Connection.hs
@@ -1,275 +0,0 @@-{-|-Module      : Database.MySQL.Connection-Description : Connection managment-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--This is an internal module, the 'MySQLConn' type should not directly acessed to user.---}--module Database.MySQL.Connection where--import           Control.Applicative-import           Control.Exception               (Exception, bracketOnError,-                                                  throwIO, catch, SomeException)-import           Control.Monad-import qualified Crypto.Hash                     as Crypto-import qualified Data.Binary                     as Binary-import qualified Data.Binary.Put                 as Binary-import           Data.Bits-import qualified Data.ByteArray                  as BA-import           Data.ByteString                 (ByteString)-import qualified Data.ByteString                 as B-import qualified Data.ByteString.Lazy            as L-import qualified Data.ByteString.Unsafe          as B-import           Data.IORef                      (IORef, newIORef, readIORef,-                                                  writeIORef)-import           Data.Typeable-import           Data.Word-import           Database.MySQL.Protocol.Auth-import           Database.MySQL.Protocol.Command-import           Database.MySQL.Protocol.Packet-import           Network.Socket                  (HostName, PortNumber)-import           System.IO.Streams               (InputStream)-import qualified System.IO.Streams               as Stream-import qualified System.IO.Streams.TCP           as TCP-import qualified Data.Connection                 as TCP-------------------------------------------------------------------------------------- | 'MySQLConn' wrap both 'InputStream' and 'OutputStream' for MySQL 'Packet'.------ You shouldn't use one 'MySQLConn' in different thread, if you do that,--- consider protecting it with a @MVar@.----data MySQLConn = MySQLConn {-        mysqlRead        :: {-# UNPACK #-} !(InputStream  Packet)-    ,   mysqlWrite       :: (Packet -> IO ())-    ,   mysqlCloseSocket :: IO ()-    ,   isConsumed       :: {-# UNPACK #-} !(IORef Bool)-    }---- | Everything you need to establish a MySQL connection.------ To setup a TLS connection, use module "Database.MySQL.TLS" or "Database.MySQL.OpenSSL".----data ConnectInfo = ConnectInfo-    { ciHost     :: HostName-    , ciPort     :: PortNumber-    , ciDatabase :: ByteString-    , ciUser     :: ByteString-    , ciPassword :: ByteString-    , ciCharset  :: Word8-    } deriving Show---- | A simple 'ConnectInfo' targeting localhost with @user=root@ and empty password.------  Default charset is set to @utf8_general_ci@ to support older(< 5.5.3) MySQL versions,---  but be aware this is a partial utf8 encoding, you may want to use 'defaultConnectInfoMB4'---  instead to support full utf8 charset(emoji, etc.). You can query your server's support---  with @SELECT id, collation_name FROM information_schema.collations ORDER BY id;@----defaultConnectInfo :: ConnectInfo-defaultConnectInfo = ConnectInfo "127.0.0.1" 3306 "" "root" "" utf8_general_ci---- | 'defaultConnectInfo' with charset set to @utf8mb4_unicode_ci@------ This is recommanded on any MySQL server version >= 5.5.3.----defaultConnectInfoMB4 :: ConnectInfo-defaultConnectInfoMB4 = ConnectInfo "127.0.0.1" 3306 "" "root" "" utf8mb4_unicode_ci--utf8_general_ci :: Word8-utf8_general_ci = 33--utf8mb4_unicode_ci :: Word8-utf8mb4_unicode_ci = 224-------------------------------------------------------------------------------------- | Socket buffer size.------ maybe exposed to 'ConnectInfo' laster?----bUFSIZE :: Int-bUFSIZE = 16384---- | Establish a MySQL connection.----connect :: ConnectInfo -> IO MySQLConn-connect = fmap snd . connectDetail---- | Establish a MySQL connection with 'Greeting' back, so you can find server's version .etc.----connectDetail :: ConnectInfo -> IO (Greeting, MySQLConn)-connectDetail (ConnectInfo host port db user pass charset)-    = bracketOnError open TCP.close go-  where-    open  = connectWithBufferSize host port bUFSIZE-    go c  = do-        let is = TCP.source c-        is' <- decodeInputStream is-        p <- readPacket is'-        greet <- decodeFromPacket p-        let auth = mkAuth db user pass charset greet-        write c $ encodeToPacket 1 auth-        q <- readPacket is'-        if isOK q-        then do-            consumed <- newIORef True-            let waitNotMandatoryOK = catch-                    (void (waitCommandReply is'))           -- server will either reply an OK packet-                    ((\ _ -> return ()) :: SomeException -> IO ())   -- or directy close the connection-                conn = MySQLConn is'-                    (write c)-                    (writeCommand COM_QUIT (write c) >> waitNotMandatoryOK >> TCP.close c)-                    consumed-            return (greet, conn)-        else TCP.close c >> decodeFromPacket q >>= throwIO . ERRException--    connectWithBufferSize h p bs = TCP.connectSocket h p >>= TCP.socketToConnection bs-    write c a = TCP.send c $ Binary.runPut . Binary.put $ a--mkAuth :: ByteString -> ByteString -> ByteString -> Word8 -> Greeting -> Auth-mkAuth db user pass charset greet =-    let salt = greetingSalt1 greet `B.append` greetingSalt2 greet-        scambleBuf = scramble salt pass-    in Auth clientCap clientMaxPacketSize charset user scambleBuf db-  where-    scramble :: ByteString -> ByteString -> ByteString-    scramble salt pass'-        | B.null pass' = B.empty-        | otherwise   = B.pack (B.zipWith xor sha1pass withSalt)-        where sha1pass = sha1 pass'-              withSalt = sha1 (salt `B.append` sha1 sha1pass)--    sha1 :: ByteString -> ByteString-    sha1 = BA.convert . (Crypto.hash :: ByteString -> Crypto.Digest Crypto.SHA1)---- | A specialized 'decodeInputStream' here for speed-decodeInputStream :: InputStream ByteString -> IO (InputStream Packet)-decodeInputStream is = Stream.makeInputStream $ do-    bs <- Stream.readExactly 4 is-    let len =  fromIntegral (bs `B.unsafeIndex` 0)-           .|. fromIntegral (bs `B.unsafeIndex` 1) `shiftL` 8-           .|. fromIntegral (bs `B.unsafeIndex` 2) `shiftL` 16-        seqN = bs `B.unsafeIndex` 3-    body <- loopRead [] len is-    return . Just $ Packet len seqN body-  where-    loopRead acc 0 _  = return $! L.fromChunks (reverse acc)-    loopRead acc k is' = do-        bs <- Stream.read is'-        case bs of Nothing -> throwIO NetworkException-                   Just bs' -> do let l = fromIntegral (B.length bs')-                                  if l >= k-                                  then do-                                      let (a, rest) = B.splitAt (fromIntegral k) bs'-                                      unless (B.null rest) (Stream.unRead rest is')-                                      return $! L.fromChunks (reverse (a:acc))-                                  else do-                                      let k' = k - l-                                      k' `seq` loopRead (bs':acc) k' is'---- | Close a MySQL connection.----close :: MySQLConn -> IO ()-close (MySQLConn _ _ closeSocket _) = closeSocket---- | Send a 'COM_PING'.----ping :: MySQLConn -> IO OK-ping = flip command COM_PING------------------------------------------------------------------------------------- helpers---- | Send a 'Command' which don't return a resultSet.----command :: MySQLConn -> Command -> IO OK-command conn@(MySQLConn is os _ _) cmd = do-    guardUnconsumed conn-    writeCommand cmd os-    waitCommandReply is-{-# INLINE command #-}--waitCommandReply :: InputStream Packet -> IO OK-waitCommandReply is = do-    p <- readPacket is-    if  | isERR p -> decodeFromPacket p >>= throwIO . ERRException-        | isOK  p -> decodeFromPacket p-        | otherwise -> throwIO (UnexpectedPacket p)-{-# INLINE waitCommandReply #-}--waitCommandReplys :: InputStream Packet -> IO [OK]-waitCommandReplys is = do-    p <- readPacket is-    if  | isERR p -> decodeFromPacket p >>= throwIO . ERRException-        | isOK  p -> do ok <- decodeFromPacket p-                        if isThereMore ok-                        then (ok :) <$> waitCommandReplys is-                        else return [ok]-        | otherwise -> throwIO (UnexpectedPacket p)-{-# INLINE waitCommandReplys #-}--readPacket :: InputStream Packet -> IO Packet-readPacket is = Stream.read is >>= maybe-    (throwIO NetworkException)-    (\ p@(Packet len _ bs) -> if len < 16777215 then return p else go len [bs])-  where-    go len acc = Stream.read is >>= maybe-        (throwIO NetworkException)-        (\ (Packet len' seqN bs) -> do-            let len'' = len + len'-                acc' = bs:acc-            if len' < 16777215-            then return (Packet len'' seqN (L.concat . reverse $ acc'))-            else len'' `seq` go len'' acc'-        )-{-# INLINE readPacket #-}--writeCommand :: Command -> (Packet -> IO ()) -> IO ()-writeCommand a writePacket = let bs = Binary.runPut (putCommand a) in-    go (fromIntegral (L.length bs)) 0 bs writePacket-  where-    go len seqN bs writePacket' = do-        if len < 16777215-        then writePacket (Packet len seqN bs)-        else do-            let (bs', rest) = L.splitAt 16777215 bs-                seqN' = seqN + 1-                len'  = len - 16777215--            writePacket (Packet 16777215 seqN bs')-            seqN' `seq` len' `seq` go len' seqN' rest writePacket'-{-# INLINE writeCommand #-}--guardUnconsumed :: MySQLConn -> IO ()-guardUnconsumed (MySQLConn _ _ _ consumed) = do-    c <- readIORef consumed-    unless c (throwIO UnconsumedResultSet)-{-# INLINE guardUnconsumed #-}--writeIORef' :: IORef a -> a -> IO ()-writeIORef' ref x = x `seq` writeIORef ref x-{-# INLINE writeIORef' #-}------------------------------------------------------------------------------------- Exceptions--data NetworkException = NetworkException deriving (Typeable, Show)-instance Exception NetworkException--data UnconsumedResultSet = UnconsumedResultSet deriving (Typeable, Show)-instance Exception UnconsumedResultSet--data ERRException = ERRException ERR deriving (Typeable, Show)-instance Exception ERRException--data UnexpectedPacket = UnexpectedPacket Packet deriving (Typeable, Show)-instance Exception UnexpectedPacket-
− Database/MySQL/Protocol/Auth.hs
@@ -1,194 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -funbox-strict-fields #-}--{-|-Module      : Database.MySQL.Protocol.Auth-Description : MySQL Auth Packets-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--Auth related packet.---}--module Database.MySQL.Protocol.Auth where--import           Control.Applicative-import           Control.Monad-import           Data.Binary-import           Data.Binary.Get-import           Data.Binary.Parser-import           Data.Binary.Put-import qualified Data.ByteString                as B-import           Data.ByteString.Char8          as BC-import           Data.Bits-import           Database.MySQL.Protocol.Packet------------------------------------------------------------------------------------- Authentications--#define CLIENT_LONG_PASSWORD                  0x00000001-#define CLIENT_FOUND_ROWS                     0x00000002-#define CLIENT_LONG_FLAG                      0x00000004-#define CLIENT_CONNECT_WITH_DB                0x00000008-#define CLIENT_NO_SCHEMA                      0x00000010-#define CLIENT_COMPRESS                       0x00000020-#define CLIENT_ODBC                           0x00000040-#define CLIENT_LOCAL_FILES                    0x00000080-#define CLIENT_IGNORE_SPACE                   0x00000100-#define CLIENT_PROTOCOL_41                    0x00000200-#define CLIENT_INTERACTIVE                    0x00000400-#define CLIENT_SSL                            0x00000800-#define CLIENT_IGNORE_SIGPIPE                 0x00001000-#define CLIENT_TRANSACTIONS                   0x00002000-#define CLIENT_RESERVED                       0x00004000-#define CLIENT_SECURE_CONNECTION              0x00008000-#define CLIENT_MULTI_STATEMENTS               0x00010000-#define CLIENT_MULTI_RESULTS                  0x00020000-#define CLIENT_PS_MULTI_RESULTS               0x00040000-#define CLIENT_PLUGIN_AUTH                    0x00080000-#define CLIENT_CONNECT_ATTRS                  0x00100000-#define CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA 0x00200000--data Greeting = Greeting-    { greetingProtocol :: !Word8-    , greetingVersion  :: !B.ByteString-    , greetingConnId   :: !Word32-    , greetingSalt1    :: !B.ByteString-    , greetingCaps     :: !Word32-    , greetingCharset  :: !Word8-    , greetingStatus   :: !Word16-    , greetingSalt2    :: !B.ByteString-    , greetingAuthPlugin :: !B.ByteString-    } deriving (Show, Eq)--putGreeting :: Greeting -> Put-putGreeting (Greeting pv sv cid salt1 cap charset st salt2 authPlugin) = do-    putWord8 pv-    putByteString sv-    putWord8 0x00-    putWord32le cid-    putByteString salt1-    let capL = fromIntegral cap .|. 0xFF-        capH = fromIntegral (cap `shiftR` 16) .|. 0xFF-    putWord16le capL-    putWord8 charset-    putWord16le st-    putWord16le capH-    putWord8 (fromIntegral $ B.length salt2)-    replicateM_ 10 (putWord8 0x00)-    when (cap .&. CLIENT_SECURE_CONNECTION /= 0)-        (putByteString salt2)-    when (cap .&. CLIENT_PLUGIN_AUTH /= 0)-        (putByteString authPlugin)--getGreeting :: Get Greeting-getGreeting = do-    pv <- getWord8-    sv <- getByteStringNul-    cid <- getWord32le-    salt1 <- getByteString 8-    skipN 1  -- 0x00-    capL <- getWord16le-    charset <- getWord8-    status <- getWord16le-    capH <- getWord16le-    let cap = fromIntegral capH `shiftL` 16 .|. fromIntegral capL-    authPluginLen <- getWord8   -- this will issue an unused warning, see the notes below-    skipN 10 -- 10 * 0x00-    salt2 <- if (cap .&. CLIENT_SECURE_CONNECTION) == 0-        then pure B.empty-        else getByteStringNul   -- This is different with the MySQL document here-                                -- The doc said we should expect a MAX(13, length of auth-plugin-data - 8)-                                -- length bytes, but doing so stop us from login-                                -- anyway 'getByteStringNul' works perfectly here.--    authPlugin <- if (cap .&. CLIENT_PLUGIN_AUTH) == 0-        then pure B.empty-        else getByteStringNul--    return (Greeting pv sv cid salt1 cap charset status salt2 authPlugin)--instance Binary Greeting where-    get = getGreeting-    put = putGreeting--data Auth = Auth-    { authCaps      :: !Word32-    , authMaxPacket :: !Word32-    , authCharset   :: !Word8-    , authName      :: !ByteString-    , authPassword  :: !ByteString-    , authSchema    :: !ByteString-    } deriving (Show, Eq)--getAuth :: Get Auth-getAuth = do-    a <- getWord32le-    m <- getWord32le-    c <- getWord8-    skipN 23-    n <- getByteStringNul-    return $ Auth a m c n B.empty B.empty--putAuth :: Auth -> Put-putAuth (Auth cap m c n p s) = do-    putWord32le cap-    putWord32le m-    putWord8 c-    replicateM_ 23 (putWord8 0x00)-    putByteString n >> putWord8 0x00-    putWord8 $ fromIntegral (B.length p)-    putByteString p-    putByteString s-    putWord8 0x00--instance Binary Auth where-    get = getAuth-    put = putAuth--data SSLRequest = SSLRequest-    { sslReqCaps      :: !Word32-    , sslReqMaxPacket :: !Word32-    , sslReqCharset   :: !Word8-    } deriving (Show, Eq)--getSSLRequest :: Get SSLRequest-getSSLRequest = SSLRequest <$> getWord32le <*> getWord32le <*> getWord8 <* skipN 23--putSSLRequest :: SSLRequest -> Put-putSSLRequest (SSLRequest cap m c) = do-    putWord32le cap-    putWord32le m-    putWord8 c-    replicateM_ 23 (putWord8 0x00)--instance Binary SSLRequest where-    get = getSSLRequest-    put = putSSLRequest------------------------------------------------------------------------------------- default Capability Flags--clientCap :: Word32-clientCap =  CLIENT_LONG_PASSWORD-                .|. CLIENT_LONG_FLAG-                .|. CLIENT_CONNECT_WITH_DB-                .|. CLIENT_IGNORE_SPACE-                .|. CLIENT_PROTOCOL_41-                .|. CLIENT_TRANSACTIONS-                .|. CLIENT_MULTI_STATEMENTS-                .|. CLIENT_SECURE_CONNECTION--clientMaxPacketSize :: Word32-clientMaxPacketSize = 0x00ffffff :: Word32---supportTLS :: Word32 -> Bool-supportTLS x = (x .&. CLIENT_SSL) /= 0--sslRequest :: Word8 -> SSLRequest-sslRequest charset = SSLRequest (clientCap .|. CLIENT_SSL) clientMaxPacketSize charset
− Database/MySQL/Protocol/ColumnDef.hs
@@ -1,176 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -funbox-strict-fields #-}--{-|-Module      : Database.MySQL.Protocol.ColumnDef-Description : MySQL field type-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--Column definition(aka. field type).---}--module Database.MySQL.Protocol.ColumnDef where--import           Control.Applicative-import           Data.Binary-import           Data.Binary.Get-import           Data.Binary.Parser-import           Data.Binary.Put-import           Data.Bits                      ((.&.))-import           Data.ByteString                (ByteString)-import           Database.MySQL.Protocol.Packet-------------------------------------------------------------------------------------  Resultset---- | A description of a field (column) of a table.-data ColumnDef = ColumnDef-    { -- fieldCatalog :: !ByteString              -- ^ const 'def'-      columnDB        ::  !ByteString             -- ^ Database for table.-    , columnTable     ::  !ByteString             -- ^ Table of column, if column was a field.-    , columnOrigTable ::  !ByteString             -- ^ Original table name, if table was an alias.-    , columnName      ::  !ByteString             -- ^ Name of column.-    , columnOrigName  ::  !ByteString             -- ^ Original column name, if an alias.-    , columnCharSet   ::  !Word16                 -- ^ Character set number.-    , columnLength    ::  !Word32                 -- ^ Width of column (create length).-    , columnType      ::  !FieldType-    , columnFlags     ::  !Word16                 -- ^ Div flags.-    , columnDecimals  ::  !Word8                  -- ^ Number of decimals in field.-    } deriving (Show, Eq)--getField :: Get ColumnDef-getField = ColumnDef-        <$> (skipN 4                 -- const "def"-         *> getLenEncBytes)         -- db-        <*> getLenEncBytes          -- table-        <*> getLenEncBytes          -- origTable-        <*> getLenEncBytes          -- name-        <*> getLenEncBytes          -- origName-        <*  skipN 1                  -- const 0x0c-        <*> getWord16le             -- charset-        <*> getWord32le             -- length-        <*> getFieldType            -- type-        <*> getWord16le             -- flags-        <*> getWord8                -- decimals-        <* skipN 2                   -- const 0x00 0x00-{-# INLINE getField #-}--putField :: ColumnDef -> Put-putField (ColumnDef db tbl otbl name oname charset len typ flags dec) = do-    putLenEncBytes "def"-    putLenEncBytes db-    putLenEncBytes tbl-    putLenEncBytes otbl-    putLenEncBytes name-    putLenEncBytes oname-    putWord16le charset-    putWord32le len-    putFieldType typ-    putWord16le  flags-    putWord8 dec-    putWord16le 0X0000-{-# INLINE putField #-}--instance Binary ColumnDef where-    get = getField-    {-# INLINE get #-}-    put = putField-    {-# INLINE put #-}---- | @newtype@ around 'Word8' for represent @MySQL_TYPE@, We don't use sum type here for speed reason.----newtype FieldType = FieldType Word8 deriving (Show, Eq)--mySQLTypeDecimal, mySQLTypeTiny, mySQLTypeShort, mySQLTypeLong, mySQLTypeFloat :: FieldType-mySQLTypeDouble, mySQLTypeNull, mySQLTypeTimestamp, mySQLTypeLongLong, mySQLTypeInt24 :: FieldType-mySQLTypeDate, mySQLTypeTime, mySQLTypeDateTime, mySQLTypeYear, mySQLTypeNewDate, mySQLTypeVarChar :: FieldType-mySQLTypeBit, mySQLTypeTimestamp2, mySQLTypeDateTime2, mySQLTypeTime2, mySQLTypeNewDecimal :: FieldType-mySQLTypeEnum, mySQLTypeSet, mySQLTypeTinyBlob, mySQLTypeMediumBlob, mySQLTypeLongBlob :: FieldType-mySQLTypeBlob, mySQLTypeVarString, mySQLTypeString, mySQLTypeGeometry :: FieldType--mySQLTypeDecimal        = FieldType 0x00-mySQLTypeTiny           = FieldType 0x01-mySQLTypeShort          = FieldType 0x02-mySQLTypeLong           = FieldType 0x03-mySQLTypeFloat          = FieldType 0x04-mySQLTypeDouble         = FieldType 0x05-mySQLTypeNull           = FieldType 0x06-mySQLTypeTimestamp      = FieldType 0x07-mySQLTypeLongLong       = FieldType 0x08-mySQLTypeInt24          = FieldType 0x09-mySQLTypeDate           = FieldType 0x0a-mySQLTypeTime           = FieldType 0x0b-mySQLTypeDateTime       = FieldType 0x0c-mySQLTypeYear           = FieldType 0x0d-mySQLTypeNewDate        = FieldType 0x0e-mySQLTypeVarChar        = FieldType 0x0f-mySQLTypeBit            = FieldType 0x10-mySQLTypeTimestamp2     = FieldType 0x11-mySQLTypeDateTime2      = FieldType 0x12-mySQLTypeTime2          = FieldType 0x13-mySQLTypeNewDecimal     = FieldType 0xf6-mySQLTypeEnum           = FieldType 0xf7-mySQLTypeSet            = FieldType 0xf8-mySQLTypeTinyBlob       = FieldType 0xf9-mySQLTypeMediumBlob     = FieldType 0xfa-mySQLTypeLongBlob       = FieldType 0xfb-mySQLTypeBlob           = FieldType 0xfc-mySQLTypeVarString      = FieldType 0xfd-mySQLTypeString         = FieldType 0xfe-mySQLTypeGeometry       = FieldType 0xff--getFieldType :: Get FieldType-getFieldType = FieldType <$> getWord8-{-# INLINE getFieldType #-}--putFieldType :: FieldType -> Put-putFieldType (FieldType t) = putWord8 t-{-# INLINE putFieldType #-}--instance Binary FieldType where-    get = getFieldType-    {-# INLINE get #-}-    put = putFieldType-    {-# INLINE put #-}-------------------------------------------------------------------------------------  Field flags--#define NOT_NULL_FLAG         1-#define PRI_KEY_FLAG          2-#define UNIQUE_KEY_FLAG       4-#define MULT_KEY_FLAG         8-#define BLOB_FLAG             16-#define UNSIGNED_FLAG         32-#define ZEROFILL_FLAG         64-#define BINARY_FLAG           128-#define ENUM_FLAG             256-#define AUTO_INCREMENT_FLAG   512-#define TIMESTAMP_FLAG        1024-#define SET_FLAG              2048-#define NO_DEFAULT_VALUE_FLAG 4096-#define PART_KEY_FLAG         16384-#define NUM_FLAG              32768--flagNotNull, flagPrimaryKey, flagUniqueKey, flagMultipleKey, flagBlob, flagUnsigned, flagZeroFill :: Word16 -> Bool-flagBinary, flagEnum, flagAutoIncrement, flagTimeStamp, flagSet, flagNoDefaultValue, flagPartKey, flagNumeric :: Word16 -> Bool-flagNotNull        flags = flags .&. NOT_NULL_FLAG         == NOT_NULL_FLAG-flagPrimaryKey     flags = flags .&. PRI_KEY_FLAG          == PRI_KEY_FLAG-flagUniqueKey      flags = flags .&. UNIQUE_KEY_FLAG       == UNIQUE_KEY_FLAG-flagMultipleKey    flags = flags .&. MULT_KEY_FLAG         == MULT_KEY_FLAG-flagBlob           flags = flags .&. BLOB_FLAG             == BLOB_FLAG-flagUnsigned       flags = flags .&. UNSIGNED_FLAG         == UNSIGNED_FLAG-flagZeroFill       flags = flags .&. ZEROFILL_FLAG         == ZEROFILL_FLAG-flagBinary         flags = flags .&. BINARY_FLAG           == BINARY_FLAG-flagEnum           flags = flags .&. ENUM_FLAG             == ENUM_FLAG-flagAutoIncrement  flags = flags .&. AUTO_INCREMENT_FLAG   == AUTO_INCREMENT_FLAG-flagTimeStamp      flags = flags .&. TIMESTAMP_FLAG        == TIMESTAMP_FLAG-flagSet            flags = flags .&. SET_FLAG              == SET_FLAG-flagNoDefaultValue flags = flags .&. NO_DEFAULT_VALUE_FLAG == NO_DEFAULT_VALUE_FLAG-flagPartKey        flags = flags .&. PART_KEY_FLAG         == PART_KEY_FLAG-flagNumeric        flags = flags .&. NUM_FLAG              == NUM_FLAG
− Database/MySQL/Protocol/Command.hs
@@ -1,108 +0,0 @@-{-# OPTIONS_GHC -funbox-strict-fields #-}--{-|-Module      : Database.MySQL.Protocol.Command-Description : MySQL commands-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--Common MySQL commands supports.---}--module Database.MySQL.Protocol.Command where--import           Control.Applicative-import           Control.Monad-import           Data.Binary-import           Data.Binary.Get-import           Data.Binary.Parser-import           Data.Binary.Put-import           Data.ByteString                    (ByteString)-import qualified Data.ByteString.Lazy               as L-import           Database.MySQL.Protocol.MySQLValue-import           Database.MySQL.Protocol.Packet-------------------------------------------------------------------------------------  Commands--type StmtID = Word32---- | All support MySQL commands.----data Command-    = COM_QUIT                                    -- ^ 0x01-    | COM_INIT_DB        !ByteString              -- ^ 0x02-    | COM_QUERY          !L.ByteString            -- ^ 0x03-    | COM_PING                                    -- ^ 0x0E-    | COM_BINLOG_DUMP    !Word32 !Word16 !Word32 !ByteString -- ^ 0x12-            -- binlog-pos, flags(0x01), server-id, binlog-filename-    | COM_REGISTER_SLAVE !Word32 !ByteString !ByteString !ByteString !Word16 !Word32 !Word32 -- ^ 0x15-            -- server-id, slaves hostname, slaves user, slaves password,  slaves port, replication rank(ignored), master-id(usually 0)-    | COM_STMT_PREPARE   !L.ByteString            -- ^ 0x16 statement-    | COM_STMT_EXECUTE   !StmtID ![MySQLValue] !BitMap -- ^ 0x17 stmtId, params-    | COM_STMT_CLOSE     !StmtID                  -- ^ 0x19 stmtId-    | COM_STMT_RESET     !StmtID                  -- ^ 0x1A stmtId-    | COM_UNSUPPORTED-   deriving (Show, Eq)--putCommand :: Command -> Put-putCommand COM_QUIT              = putWord8 0x01-putCommand (COM_INIT_DB db)      = putWord8 0x02 >> putByteString db-putCommand (COM_QUERY q)         = putWord8 0x03 >> putLazyByteString q-putCommand COM_PING              = putWord8 0x0E-putCommand (COM_BINLOG_DUMP pos flags sid fname) = do-    putWord8 0x12-    putWord32le pos-    putWord16le flags-    putWord32le sid-    putByteString fname-putCommand (COM_REGISTER_SLAVE sid shost susr spass sport rrank mid) = do-    putWord8 0x15-    putWord32le sid-    putLenEncBytes shost-    putLenEncBytes susr-    putLenEncBytes spass-    putWord16le sport-    putWord32le rrank-    putWord32le mid-putCommand (COM_STMT_PREPARE stmt) = putWord8 0x16 >> putLazyByteString stmt-putCommand (COM_STMT_EXECUTE stid params nullmap) = do-    putWord8 0x17-    putWord32le stid-    putWord8 0x00 -- we only use @CURSOR_TYPE_NO_CURSOR@ here-    putWord32le 1 -- const 1-    unless (null params) $ do-        putByteString (fromBitMap nullmap)-        putWord8 0x01    -- always use new-params-bound-flag-        mapM_ putParamMySQLType params-        forM_ params putBinaryField--putCommand (COM_STMT_CLOSE stid) = putWord8 0x19 >> putWord32le stid-putCommand (COM_STMT_RESET stid) = putWord8 0x1A >> putWord32le stid-putCommand _                     = error "unsupported command"-------------------------------------------------------------------------------------  Prepared statment related---- | call 'isOK' with this packet return true-data StmtPrepareOK = StmtPrepareOK-    { stmtId        :: !StmtID-    , stmtColumnCnt :: !Int-    , stmtParamCnt  :: !Int-    , stmtWarnCnt   :: !Int-    } deriving (Show, Eq)--getStmtPrepareOK :: Get StmtPrepareOK-getStmtPrepareOK = do-    skipN 1 -- OK byte-    stmtid <- getWord32le-    cc <- fromIntegral <$> getWord16le-    pc <- fromIntegral <$> getWord16le-    skipN 1 -- reserved-    wc <- fromIntegral <$> getWord16le-    return (StmtPrepareOK stmtid cc pc wc)-{-# INLINE getStmtPrepareOK #-}
− Database/MySQL/Protocol/Escape.hs
@@ -1,107 +0,0 @@-{-# LANGUAGE BangPatterns #-}--{-|-Module      : Database.MySQL.Protocol.Escape-Description : Pure haskell mysql escape-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--This module provide escape machinery for bytes and text types.--reference: <http://dev.mysql.com/doc/refman/5.7/en/string-literals.html>--    * Escape Sequence	Character Represented by Sequence-    * \0              	An ASCII NUL (X'00') character-    * \'              	A single quote (“'”) character-    * \"              	A double quote (“"”) character-    * \b              	A backspace character-    * \n              	A newline (linefeed) character-    * \r              	A carriage return character-    * \t              	A tab character-    * \Z              	ASCII 26 (Control+Z); see note following the table-    * \\              	A backslash (“\”) character-    * \%              	A “%” character; see note following the table-    * \_              	A “_” character; see note following the table--The @\%@ and @\_@ sequences are used to search for literal instances of @%@ and @_@ in pattern-matching contexts where they would otherwise be interpreted as wildcard characters, so we won't auto escape @%@ or @_@ here.---}--module Database.MySQL.Protocol.Escape where--import           Data.ByteString          (ByteString)-import qualified Data.ByteString.Internal as B-import           Data.Text                (Text)-import qualified Data.Text.Array          as TA-import qualified Data.Text.Internal       as T-import           Data.Word-import           Foreign.ForeignPtr       (withForeignPtr)-import           Foreign.Ptr              (Ptr, minusPtr, plusPtr)-import           Foreign.Storable         (peek, poke, pokeByteOff)-import           GHC.IO                   (unsafeDupablePerformIO)--escapeText :: Text -> Text-escapeText (T.Text arr off len)-    | len <= 0  = T.empty-    | otherwise =-        let (arr', len') =  TA.run2 $ do-                marr <- TA.new (len * 2)-                loop arr (off + len) marr off 0-        in T.Text arr' 0 len'-  where-    escape c marr ix = do-        TA.unsafeWrite marr ix 92-        TA.unsafeWrite marr (ix+1) c--    loop oarr oend marr !ix !ix'-        | ix == oend = return (marr, ix')-        | otherwise  = do-            let c = TA.unsafeIndex oarr ix-                go1 = loop oarr oend marr (ix+1) (ix'+1)-                go2 = loop oarr oend marr (ix+1) (ix'+2)-            if  | c >= 0xD800 && c <= 0xDBFF  -> do let c2 = TA.unsafeIndex oarr (ix+1)-                                                    TA.unsafeWrite marr ix' c-                                                    TA.unsafeWrite marr (ix'+1) c2-                                                    loop oarr oend marr (ix+2) (ix'+2)-                | c == 0-                    || c == 39-                    || c == 34 -> escape c   marr ix' >> go2 -- \0 \' \"-                | c == 8       -> escape 98  marr ix' >> go2 -- \b-                | c == 10      -> escape 110 marr ix' >> go2 -- \n-                | c == 13      -> escape 114 marr ix' >> go2 -- \r-                | c == 9       -> escape 116 marr ix' >> go2 -- \t-                | c == 26      -> escape 90  marr ix' >> go2 -- \Z-                | c == 92      -> escape 92  marr ix' >> go2 -- \\--                | otherwise    -> TA.unsafeWrite marr ix' c >> go1--escapeBytes :: ByteString -> ByteString-escapeBytes (B.PS fp s len) = unsafeDupablePerformIO $ withForeignPtr fp $ \ a ->-    B.createUptoN (len * 2) $ \ b -> do-        b' <- loop (a `plusPtr` s) (a `plusPtr` s `plusPtr` len) b-        return (b' `minusPtr` b)-  where-    escape :: Word8 -> Ptr Word8 -> IO (Ptr Word8)-    escape c p = do-        poke p 92-        pokeByteOff p 1 c-        return (p `plusPtr` 2)--    loop !a aend !b-        | a == aend = return b-        | otherwise = do-            c <- peek a-            if  | c == 0-                    || c == 39-                    || c == 34 -> escape c   b >>= loop (a `plusPtr` 1) aend -- \0 \' \"-                | c == 8       -> escape 98  b >>= loop (a `plusPtr` 1) aend -- \b-                | c == 10      -> escape 110 b >>= loop (a `plusPtr` 1) aend -- \n-                | c == 13      -> escape 114 b >>= loop (a `plusPtr` 1) aend -- \r-                | c == 9       -> escape 116 b >>= loop (a `plusPtr` 1) aend -- \t-                | c == 26      -> escape 90  b >>= loop (a `plusPtr` 1) aend -- \Z-                | c == 92      -> escape 92  b >>= loop (a `plusPtr` 1) aend -- \\--                | otherwise    -> poke b c >> loop (a `plusPtr` 1) aend (b `plusPtr` 1)
− Database/MySQL/Protocol/MySQLValue.hs
@@ -1,567 +0,0 @@-{-# OPTIONS_GHC -funbox-strict-fields #-}--{-|-Module      : Database.MySQL.Protocol.MySQLValue-Description : Text and binary protocol-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--Core text and binary row decoder/encoder machinery.---}--module Database.MySQL.Protocol.MySQLValue-  ( -- * MySQLValue decoder and encoder-    MySQLValue(..)-  , putParamMySQLType-  , getTextField-  , putTextField-  , getTextRow-  , getTextRowVector-  , getBinaryField-  , putBinaryField-  , getBinaryRow-  , getBinaryRowVector-  -- * Internal utilities-  , getBits-  , BitMap(..)-  , isColumnSet-  , isColumnNull-  , makeNullMap-  ) where--import qualified Blaze.Text                         as Textual-import           Control.Applicative-import           Control.Monad-import           Data.Binary.Put-import           Data.Binary.Parser-import           Data.Binary.IEEE754-import           Data.Bits-import           Data.ByteString                    (ByteString)-import qualified Data.ByteString                    as B-import qualified Data.ByteString.Builder            as BB-import           Data.ByteString.Builder.Scientific (FPFormat (..),-                                                     formatScientificBuilder)-import qualified Data.ByteString.Char8              as BC-import qualified Data.ByteString.Lazy               as L-import qualified Data.ByteString.Lex.Fractional     as LexFrac-import qualified Data.ByteString.Lex.Integral       as LexInt-import qualified Data.ByteString.Unsafe             as B-import           Data.Fixed                         (Pico)-import           Data.Int-import           Data.Scientific                    (Scientific)-import           Data.Text                          (Text)-import qualified Data.Text.Encoding                 as T-import           Data.Time.Calendar                 (Day, fromGregorian,-                                                     toGregorian)-import           Data.Time.Format                   (defaultTimeLocale,-                                                     formatTime)-import           Data.Time.LocalTime                (LocalTime (..),-                                                     TimeOfDay (..))-import           Data.Word-import           Database.MySQL.Protocol.ColumnDef-import           Database.MySQL.Protocol.Escape-import           Database.MySQL.Protocol.Packet-import           GHC.Generics                       (Generic)-import qualified Data.Vector                        as V------------------------------------------------------------------------------------- | Data type mapping between MySQL values and haskell values.------ There're some subtle differences between MySQL values and haskell values:------ MySQL's @DATETIME@ and @TIMESTAMP@ are different on timezone handling:------  * DATETIME and DATE is just a represent of a calendar date, it has no timezone information involved,---  you always get the same value as you put no matter what timezone you're using with MySQL.------  * MySQL converts TIMESTAMP values from the current time zone to UTC for storage,---  and back from UTC to the current time zone for retrieval. If you put a TIMESTAMP with timezone A,---  then read it with timezone B, you may get different result because of this conversion, so always---  be careful about setting up the right timezone with MySQL, you can do it with a simple @SET time_zone = timezone;@---  for more info on timezone support, please read <http://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html>------  So we use 'LocalTime' to present both @DATETIME@ and @TIMESTAMP@, but the local here is different.------ MySQL's @TIME@ type can present time of day, but also elapsed time or a time interval between two events.--- @TIME@ values may range from @-838:59:59@ to @838:59:59@, so 'MySQLTime' values consist of a sign and a--- 'TimeOfDay' whose hour part may exceeded 24. you can use @timeOfDayToTime@ to get the absolute time interval.------ Under MySQL >= 5.7, @DATETIME@, @TIMESTAMP@ and @TIME@ may contain fractional part, which matches haskell's--- precision.----data MySQLValue-    = MySQLDecimal       !Scientific   -- ^ DECIMAL, NEWDECIMAL-    | MySQLInt8U         !Word8        -- ^ Unsigned TINY-    | MySQLInt8          !Int8         -- ^ TINY-    | MySQLInt16U        !Word16       -- ^ Unsigned SHORT-    | MySQLInt16         !Int16        -- ^ SHORT-    | MySQLInt32U        !Word32       -- ^ Unsigned LONG, INT24-    | MySQLInt32         !Int32        -- ^ LONG, INT24-    | MySQLInt64U        !Word64       -- ^ Unsigned LONGLONG-    | MySQLInt64         !Int64        -- ^ LONGLONG-    | MySQLFloat         !Float        -- ^ IEEE 754 single precision format-    | MySQLDouble        !Double       -- ^ IEEE 754 double precision format-    | MySQLYear          !Word16       -- ^ YEAR-    | MySQLDateTime      !LocalTime    -- ^ DATETIME-    | MySQLTimeStamp     !LocalTime    -- ^ TIMESTAMP-    | MySQLDate          !Day              -- ^ DATE-    | MySQLTime          !Word8 !TimeOfDay -- ^ sign(0 = non-negative, 1 = negative) hh mm ss microsecond-                                           -- The sign is OPPOSITE to binlog one !!!-    | MySQLGeometry      !ByteString       -- ^ todo: parsing to something meanful-    | MySQLBytes         !ByteString-    | MySQLBit           !Word64-    | MySQLText          !Text-    | MySQLNull-  deriving (Show, Eq, Generic)---- | Put 'FieldType' and usigned bit(0x80/0x00) for 'MySQLValue's.----putParamMySQLType :: MySQLValue -> Put-putParamMySQLType (MySQLDecimal      _)  = putFieldType mySQLTypeDecimal  >> putWord8 0x00-putParamMySQLType (MySQLInt8U        _)  = putFieldType mySQLTypeTiny     >> putWord8 0x80-putParamMySQLType (MySQLInt8         _)  = putFieldType mySQLTypeTiny     >> putWord8 0x00-putParamMySQLType (MySQLInt16U       _)  = putFieldType mySQLTypeShort    >> putWord8 0x80-putParamMySQLType (MySQLInt16        _)  = putFieldType mySQLTypeShort    >> putWord8 0x00-putParamMySQLType (MySQLInt32U       _)  = putFieldType mySQLTypeLong     >> putWord8 0x80-putParamMySQLType (MySQLInt32        _)  = putFieldType mySQLTypeLong     >> putWord8 0x00-putParamMySQLType (MySQLInt64U       _)  = putFieldType mySQLTypeLongLong >> putWord8 0x80-putParamMySQLType (MySQLInt64        _)  = putFieldType mySQLTypeLongLong >> putWord8 0x00-putParamMySQLType (MySQLFloat        _)  = putFieldType mySQLTypeFloat    >> putWord8 0x00-putParamMySQLType (MySQLDouble       _)  = putFieldType mySQLTypeDouble   >> putWord8 0x00-putParamMySQLType (MySQLYear         _)  = putFieldType mySQLTypeYear     >> putWord8 0x80-putParamMySQLType (MySQLDateTime     _)  = putFieldType mySQLTypeDateTime >> putWord8 0x00-putParamMySQLType (MySQLTimeStamp    _)  = putFieldType mySQLTypeTimestamp>> putWord8 0x00-putParamMySQLType (MySQLDate         _)  = putFieldType mySQLTypeDate     >> putWord8 0x00-putParamMySQLType (MySQLTime       _ _)  = putFieldType mySQLTypeTime     >> putWord8 0x00-putParamMySQLType (MySQLBytes        _)  = putFieldType mySQLTypeBlob     >> putWord8 0x00-putParamMySQLType (MySQLGeometry     _)  = putFieldType mySQLTypeGeometry >> putWord8 0x00-putParamMySQLType (MySQLBit          _)  = putFieldType mySQLTypeBit      >> putWord8 0x00-putParamMySQLType (MySQLText         _)  = putFieldType mySQLTypeString   >> putWord8 0x00-putParamMySQLType MySQLNull              = putFieldType mySQLTypeNull     >> putWord8 0x00------------------------------------------------------------------------------------- | Text protocol decoder-getTextField :: ColumnDef -> Get MySQLValue-getTextField f-    | t == mySQLTypeNull            = pure MySQLNull-    | t == mySQLTypeDecimal-        || t == mySQLTypeNewDecimal = feedLenEncBytes t MySQLDecimal fracLexer-    | t == mySQLTypeTiny            = if isUnsigned then feedLenEncBytes t MySQLInt8U intLexer-                                                    else feedLenEncBytes t MySQLInt8 intLexer-    | t == mySQLTypeShort           = if isUnsigned then feedLenEncBytes t MySQLInt16U intLexer-                                                    else feedLenEncBytes t MySQLInt16 intLexer-    | t == mySQLTypeLong-        || t == mySQLTypeInt24      = if isUnsigned then feedLenEncBytes t MySQLInt32U intLexer-                                                    else feedLenEncBytes t MySQLInt32 intLexer-    | t == mySQLTypeLongLong        = if isUnsigned then feedLenEncBytes t MySQLInt64U intLexer-                                                    else feedLenEncBytes t MySQLInt64 intLexer-    | t == mySQLTypeFloat           = feedLenEncBytes t MySQLFloat fracLexer-    | t == mySQLTypeDouble          = feedLenEncBytes t MySQLDouble fracLexer-    | t == mySQLTypeYear            = feedLenEncBytes t MySQLYear intLexer-    | t == mySQLTypeTimestamp-        || t == mySQLTypeTimestamp2 = feedLenEncBytes t MySQLTimeStamp $ \ bs ->-                                          LocalTime <$> dateParser bs <*> timeParser (B.unsafeDrop 11 bs)-    | t == mySQLTypeDateTime-        || t == mySQLTypeDateTime2  = feedLenEncBytes t MySQLDateTime $ \ bs ->-                                          LocalTime <$> dateParser bs <*> timeParser (B.unsafeDrop 11 bs)-    | t == mySQLTypeDate-        || t == mySQLTypeNewDate    = feedLenEncBytes t MySQLDate dateParser-    | t == mySQLTypeTime-        || t == mySQLTypeTime2      = feedLenEncBytes t id $ \ bs ->-                                          if bs `B.unsafeIndex` 0 == 45  -- '-'-                                               then MySQLTime 1 <$> timeParser (B.unsafeDrop 1 bs)-                                               else MySQLTime 0 <$> timeParser bs--    | t == mySQLTypeGeometry        = MySQLGeometry <$> getLenEncBytes-    | t == mySQLTypeVarChar-        || t == mySQLTypeEnum-        || t == mySQLTypeSet-        || t == mySQLTypeTinyBlob-        || t == mySQLTypeMediumBlob-        || t == mySQLTypeLongBlob-        || t == mySQLTypeBlob-        || t == mySQLTypeVarString-        || t == mySQLTypeString     = (if isText then MySQLText . T.decodeUtf8 else MySQLBytes) <$> getLenEncBytes--    | t == mySQLTypeBit             = MySQLBit <$> (getBits =<< getLenEncInt)--    | otherwise                     = fail $ "Database.MySQL.Protocol.MySQLValue: missing text decoder for " ++ show t-  where-    t = columnType f-    isUnsigned = flagUnsigned (columnFlags f)-    isText = columnCharSet f /= 63-    intLexer bs = fst <$> LexInt.readSigned LexInt.readDecimal bs-    fracLexer bs = fst <$> LexFrac.readSigned LexFrac.readDecimal bs-    dateParser bs = do-        (yyyy, rest) <- LexInt.readDecimal bs-        (mm, rest') <- LexInt.readDecimal (B.unsafeTail rest)-        (dd, _) <- LexInt.readDecimal (B.unsafeTail rest')-        return (fromGregorian yyyy mm dd)--    timeParser bs = do-        (hh, rest) <- LexInt.readDecimal bs-        (mm, rest') <- LexInt.readDecimal (B.unsafeTail rest)-        (ss, _) <- LexFrac.readDecimal (B.unsafeTail rest')-        return (TimeOfDay hh mm ss)---feedLenEncBytes :: FieldType -> (t -> b) -> (ByteString -> Maybe t) -> Get b-feedLenEncBytes typ con parser = do-    bs <- getLenEncBytes-    case parser bs of-        Just v -> return (con v)-        Nothing -> fail $ "Database.MySQL.Protocol.MySQLValue: parsing " ++ show typ ++ " failed, \-                          \input: " ++ BC.unpack bs-{-# INLINE feedLenEncBytes #-}------------------------------------------------------------------------------------- | Text protocol encoder-putTextField :: MySQLValue -> Put-putTextField (MySQLDecimal    n) = putBuilder (formatScientificBuilder Fixed Nothing n)-putTextField (MySQLInt8U      n) = putBuilder (Textual.integral n)-putTextField (MySQLInt8       n) = putBuilder (Textual.integral n)-putTextField (MySQLInt16U     n) = putBuilder (Textual.integral n)-putTextField (MySQLInt16      n) = putBuilder (Textual.integral n)-putTextField (MySQLInt32U     n) = putBuilder (Textual.integral n)-putTextField (MySQLInt32      n) = putBuilder (Textual.integral n)-putTextField (MySQLInt64U     n) = putBuilder (Textual.integral n)-putTextField (MySQLInt64      n) = putBuilder (Textual.integral n)-putTextField (MySQLFloat      x) = putBuilder (Textual.float x)-putTextField (MySQLDouble     x) = putBuilder (Textual.double x)-putTextField (MySQLYear       n) = putBuilder (Textual.integral n)-putTextField (MySQLDateTime  dt) = putInQuotes $-                                      putByteString (BC.pack (formatTime defaultTimeLocale "%F %T%Q" dt))-putTextField (MySQLTimeStamp dt) = putInQuotes $-                                      putByteString (BC.pack (formatTime defaultTimeLocale "%F %T%Q" dt))-putTextField (MySQLDate       d) = putInQuotes $-                                      putByteString (BC.pack (formatTime defaultTimeLocale "%F" d))-putTextField (MySQLTime  sign t) = putInQuotes $ do-                                      when (sign == 1) (putCharUtf8 '-')-                                      putByteString (BC.pack (formatTime defaultTimeLocale "%T%Q" t))-                                      -- this works even for hour > 24-putTextField (MySQLGeometry  bs) = putInQuotes $ putByteString . escapeBytes $ bs-putTextField (MySQLBytes     bs) = putInQuotes $ putByteString . escapeBytes $ bs-putTextField (MySQLText       t) = putInQuotes $-                                      putByteString . T.encodeUtf8 . escapeText $ t-putTextField (MySQLBit        b) = do putBuilder "b\'"-                                      putBuilder . execPut $ putTextBits b-                                      putCharUtf8 '\''-  where-    putTextBits :: Word64 -> Put-    putTextBits word = forM_ [63,62..0] $ \ pos ->-            if word `testBit` pos then putCharUtf8 '1' else putCharUtf8 '0'-    {-# INLINE putTextBits #-}--putTextField MySQLNull           = putBuilder "NULL"--putInQuotes :: Put -> Put-putInQuotes p = putCharUtf8 '\'' >> p >> putCharUtf8 '\''-{-# INLINE putInQuotes #-}------------------------------------------------------------------------------------- | Text row decoder-getTextRow :: [ColumnDef] -> Get [MySQLValue]-getTextRow fs = forM fs $ \ f -> do-    p <- peek-    if p == 0xFB-    then skipN 1 >> return MySQLNull-    else getTextField f-{-# INLINE getTextRow #-}--getTextRowVector :: V.Vector ColumnDef -> Get (V.Vector MySQLValue)-getTextRowVector fs = V.forM fs $ \ f -> do-    p <- peek-    if p == 0xFB-    then skipN 1 >> return MySQLNull-    else getTextField f-{-# INLINE getTextRowVector #-}------------------------------------------------------------------------------------- | Binary protocol decoder-getBinaryField :: ColumnDef -> Get MySQLValue-getBinaryField f-    | t == mySQLTypeNull              = pure MySQLNull-    | t == mySQLTypeDecimal-        || t == mySQLTypeNewDecimal   = feedLenEncBytes t MySQLDecimal fracLexer-    | t == mySQLTypeTiny              = if isUnsigned then MySQLInt8U <$> getWord8-                                                      else MySQLInt8  <$> getInt8-    | t == mySQLTypeShort             = if isUnsigned then MySQLInt16U <$> getWord16le-                                                      else MySQLInt16  <$> getInt16le-    | t == mySQLTypeLong-        || t == mySQLTypeInt24        = if isUnsigned then MySQLInt32U <$> getWord32le-                                                      else MySQLInt32  <$> getInt32le-    | t == mySQLTypeYear              = MySQLYear . fromIntegral <$> getWord16le-    | t == mySQLTypeLongLong          = if isUnsigned then MySQLInt64U <$> getWord64le-                                                      else MySQLInt64  <$> getInt64le-    | t == mySQLTypeFloat             = MySQLFloat  <$> getFloatle-    | t == mySQLTypeDouble            = MySQLDouble <$> getDoublele-    | t == mySQLTypeTimestamp-        || t == mySQLTypeTimestamp2   = do-            n <- getLenEncInt-            case n of-               0 -> pure $ MySQLTimeStamp (LocalTime (fromGregorian 0 0 0) (TimeOfDay 0 0 0))-               4 -> do-                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'-                   pure $ MySQLTimeStamp (LocalTime d (TimeOfDay 0 0 0))-               7 -> do-                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'-                   td <- TimeOfDay <$> getInt8' <*> getInt8' <*> getSecond4-                   pure $ MySQLTimeStamp (LocalTime d td)-               11 -> do-                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'-                   td <- TimeOfDay <$> getInt8' <*> getInt8' <*> getSecond8-                   pure $ MySQLTimeStamp (LocalTime d td)-               _ -> fail "Database.MySQL.Protocol.MySQLValue: wrong TIMESTAMP length"-    | t == mySQLTypeDateTime-        || t == mySQLTypeDateTime2    = do-            n <- getLenEncInt-            case n of-               0 -> pure $ MySQLDateTime (LocalTime (fromGregorian 0 0 0) (TimeOfDay 0 0 0))-               4 -> do-                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'-                   pure $ MySQLDateTime (LocalTime d (TimeOfDay 0 0 0))-               7 -> do-                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'-                   td <- TimeOfDay <$> getInt8' <*> getInt8' <*> getSecond4-                   pure $ MySQLDateTime (LocalTime d td)-               11 -> do-                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'-                   td <- TimeOfDay <$> getInt8' <*> getInt8' <*> getSecond8-                   pure $ MySQLDateTime (LocalTime d td)-               _ -> fail "Database.MySQL.Protocol.MySQLValue: wrong DATETIME length"--    | t == mySQLTypeDate-        || t == mySQLTypeNewDate      = do-            n <- getLenEncInt-            case n of-               0 -> pure $ MySQLDate (fromGregorian 0 0 0)-               4 -> MySQLDate <$> (fromGregorian <$> getYear <*> getInt8' <*> getInt8')-               _ -> fail "Database.MySQL.Protocol.MySQLValue: wrong DATE length"--    | t == mySQLTypeTime-        || t == mySQLTypeTime2        = do-            n <- getLenEncInt-            case n of-               0 -> pure $ MySQLTime 0 (TimeOfDay 0 0 0)-               8 -> do-                   sign <- getWord8   -- is_negative(1 if minus, 0 for plus)-                   d <- fromIntegral <$> getWord32le-                   h <-  getInt8'-                   MySQLTime sign <$> (TimeOfDay (d*24 + h) <$> getInt8' <*> getSecond4)--               12 -> do-                   sign <- getWord8   -- is_negative(1 if minus, 0 for plus)-                   d <- fromIntegral <$> getWord32le-                   h <-  getInt8'-                   MySQLTime sign <$> (TimeOfDay (d*24 + h) <$> getInt8' <*> getSecond8)-               _ -> fail "Database.MySQL.Protocol.MySQLValue: wrong TIME length"--    | t == mySQLTypeGeometry          = MySQLGeometry <$> getLenEncBytes-    | t == mySQLTypeVarChar-        || t == mySQLTypeEnum-        || t == mySQLTypeSet-        || t == mySQLTypeTinyBlob-        || t == mySQLTypeMediumBlob-        || t == mySQLTypeLongBlob-        || t == mySQLTypeBlob-        || t == mySQLTypeVarString-        || t == mySQLTypeString       = if isText then MySQLText . T.decodeUtf8 <$> getLenEncBytes-                                                  else MySQLBytes <$> getLenEncBytes-    | t == mySQLTypeBit               = MySQLBit <$> (getBits =<< getLenEncInt)-    | otherwise                       = fail $ "Database.MySQL.Protocol.MySQLValue:\-                                               \ missing binary decoder for " ++ show t-  where-    t = columnType f-    isUnsigned = flagUnsigned (columnFlags f)-    isText = columnCharSet f /= 63-    fracLexer bs = fst <$> LexFrac.readSigned LexFrac.readDecimal bs-    getYear :: Get Integer-    getYear = fromIntegral <$> getWord16le-    getInt8' :: Get Int-    getInt8' = fromIntegral <$> getWord8-    getSecond4 :: Get Pico-    getSecond4 = realToFrac <$> getWord8-    getSecond8 :: Get Pico-    getSecond8 = realToFrac <$> do-        s <- getInt8'-        ms <- fromIntegral <$> getWord32le :: Get Int-        pure $! (realToFrac s + realToFrac ms / 1000000 :: Pico)----- | Get a bit sequence as a Word64------ Since 'Word64' has a @Bits@ instance, it's easier to deal with in haskell.----getBits :: Int -> Get Word64-getBits bytes =-    if  | bytes == 0 || bytes == 1 -> fromIntegral <$> getWord8-        | bytes == 2 -> fromIntegral <$> getWord16be-        | bytes == 3 -> fromIntegral <$> getWord24be-        | bytes == 4 -> fromIntegral <$> getWord32be-        | bytes == 5 -> fromIntegral <$> getWord40be-        | bytes == 6 -> fromIntegral <$> getWord48be-        | bytes == 7 -> fromIntegral <$> getWord56be-        | bytes == 8 -> fromIntegral <$> getWord64be-        | otherwise  -> fail $  "Database.MySQL.Protocol.MySQLValue: \-                                \wrong bit length size: " ++ show bytes-{-# INLINE getBits #-}-------------------------------------------------------------------------------------- | Binary protocol encoder-putBinaryField :: MySQLValue -> Put-putBinaryField (MySQLDecimal    n) = putLenEncBytes . L.toStrict . BB.toLazyByteString $-                                        formatScientificBuilder Fixed Nothing n-putBinaryField (MySQLInt8U      n) = putWord8 n-putBinaryField (MySQLInt8       n) = putWord8 (fromIntegral n)-putBinaryField (MySQLInt16U     n) = putWord16le n-putBinaryField (MySQLInt16      n) = putInt16le n-putBinaryField (MySQLInt32U     n) = putWord32le n-putBinaryField (MySQLInt32      n) = putInt32le n-putBinaryField (MySQLInt64U     n) = putWord64le n-putBinaryField (MySQLInt64      n) = putInt64le n-putBinaryField (MySQLFloat      x) = putFloatle x-putBinaryField (MySQLDouble     x) = putDoublele x-putBinaryField (MySQLYear       n) = putLenEncBytes . L.toStrict . BB.toLazyByteString $-                                        Textual.integral n  -- this's really weird, it's not documented anywhere-                                                            -- we must encode year into string in binary mode!-putBinaryField (MySQLTimeStamp (LocalTime date time)) = do putWord8 11    -- always put full-                                                           putBinaryDay date-                                                           putBinaryTime' time-putBinaryField (MySQLDateTime  (LocalTime date time)) = do putWord8 11    -- always put full-                                                           putBinaryDay date-                                                           putBinaryTime' time-putBinaryField (MySQLDate    d)    = do putWord8 4-                                        putBinaryDay d-putBinaryField (MySQLTime sign t)  = do putWord8 12    -- always put full-                                        putWord8 sign-                                        putBinaryTime t-putBinaryField (MySQLGeometry bs)  = putLenEncBytes bs-putBinaryField (MySQLBytes  bs)    = putLenEncBytes bs-putBinaryField (MySQLBit    word)  = do putWord8 8     -- always put full-                                        putWord64be word-putBinaryField (MySQLText    t)    = putLenEncBytes (T.encodeUtf8 t)-putBinaryField MySQLNull           = return ()--putBinaryDay :: Day -> Put-putBinaryDay d = do let (yyyy, mm, dd) = toGregorian d-                    putWord16le (fromIntegral yyyy)-                    putWord8 (fromIntegral mm)-                    putWord8 (fromIntegral dd)-{-# INLINE putBinaryDay #-}--putBinaryTime' :: TimeOfDay -> Put-putBinaryTime' (TimeOfDay hh mm ss) = do let s = floor ss-                                             ms = floor $ (ss - realToFrac s) * 1000000-                                         putWord8 (fromIntegral hh)-                                         putWord8 (fromIntegral mm)-                                         putWord8 s-                                         putWord32le ms-{-# INLINE putBinaryTime' #-}--putBinaryTime :: TimeOfDay -> Put-putBinaryTime (TimeOfDay hh mm ss) = do let s = floor ss-                                            ms = floor $ (ss - realToFrac s) * 1000000-                                            (d, h) = hh `quotRem` 24  -- hour may exceed 24 here-                                        putWord32le (fromIntegral d)-                                        putWord8 (fromIntegral h)-                                        putWord8 (fromIntegral mm)-                                        putWord8 s-                                        putWord32le ms-{-# INLINE putBinaryTime #-}------------------------------------------------------------------------------------- | Binary row decoder------ MySQL use a special null bitmap without offset = 2 here.----getBinaryRow :: [ColumnDef] -> Int -> Get [MySQLValue]-getBinaryRow fields flen = do-    skipN 1           -- 0x00-    let maplen = (flen + 7 + 2) `shiftR` 3-    nullmap <- BitMap <$> getByteString maplen-    go fields nullmap 0-  where-    go :: [ColumnDef] -> BitMap -> Int -> Get [MySQLValue]-    go []     _       _   = pure []-    go (f:fs) nullmap pos = do-        r <- if isColumnNull nullmap pos-                then return MySQLNull-                else getBinaryField f-        let pos' = pos + 1-        rest <- pos' `seq` go fs nullmap pos'-        return (r `seq` (r : rest))-{-# INLINE getBinaryRow #-}--getBinaryRowVector :: V.Vector ColumnDef -> Int -> Get (V.Vector MySQLValue)-getBinaryRowVector fields flen = do-    skipN 1           -- 0x00-    let maplen = (flen + 7 + 2) `shiftR` 3-    nullmap <- BitMap <$> getByteString maplen-    (`V.imapM` fields) $ \ pos f ->-        if isColumnNull nullmap pos then return MySQLNull else getBinaryField f-{-# INLINE getBinaryRowVector #-}------------------------------------------------------------------------------------- | Use 'ByteString' to present a bitmap.------ When used for represent bits values, the underlining 'ByteString' follows:------  * byteString: head       -> tail---  * bit:        high bit   -> low bit------ When used as a null-map/present-map, every bit inside a byte--- is mapped to a column, the mapping order is following:------  * byteString: head -> tail---  * column:     left -> right------ We don't use 'Int64' here because there maybe more than 64 columns.----newtype BitMap = BitMap { fromBitMap :: ByteString } deriving (Eq, Show)---- | Test if a column is set(binlog protocol).------ The number counts from left to right.----isColumnSet :: BitMap -> Int -> Bool-isColumnSet (BitMap bitmap) pos =-  let i = pos `unsafeShiftR` 3-      j = pos .&. 7-  in (bitmap `B.unsafeIndex` i) `testBit` j-{-# INLINE isColumnSet #-}---- | Test if a column is null(binary protocol).------ The number counts from left to right.----isColumnNull :: BitMap -> Int -> Bool-isColumnNull (BitMap nullmap) pos =-  let-    pos' = pos + 2-    i    = pos' `unsafeShiftR` 3-    j    = pos' .&. 7-  in (nullmap `B.unsafeIndex` i) `testBit` j-{-# INLINE isColumnNull #-}---- | Make a nullmap for params(binary protocol) without offset.----makeNullMap :: [MySQLValue] -> BitMap-makeNullMap values = BitMap . B.pack $ go values 0x00 0-  where-    go :: [MySQLValue] -> Word8 -> Int -> [Word8]-    go []             byte   8  = [byte]-    go vs             byte   8  = byte : go vs 0x00 0-    go []             byte   _  = [byte]-    go (MySQLNull:vs) byte pos  = let pos' = pos + 1-                                      byte' = byte .|. bit pos-                                  in pos' `seq` byte' `seq` go vs byte' pos'-    go (_        :vs) byte pos  = let pos' = pos + 1 in pos' `seq` go vs byte pos'------------------------------------------------------------------------------------- TODO: add helpers to parse mySQLTypeGEOMETRY--- reference: https://github.com/felixge/node-mysql/blob/master/lib/protocol/Parser.js
− Database/MySQL/Protocol/Packet.hs
@@ -1,300 +0,0 @@-{-# OPTIONS_GHC -funbox-strict-fields #-}--{-|-Module      : Database.MySQL.Protocol.Packet-Description : MySQL packet type and various helpers.-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--MySQL packet decoder&encoder, and varities utility.---}--module Database.MySQL.Protocol.Packet where--import           Control.Applicative-import           Control.Exception     (Exception (..), throwIO)-import           Data.Binary.Parser-import           Data.Binary.Put-import           Data.Binary           (Binary(..), encode)-import           Data.Bits-import qualified Data.ByteString       as B-import           Data.ByteString.Char8 as BC-import qualified Data.ByteString.Lazy  as L-import           Data.Int.Int24-import           Data.Int-import           Data.Word-import           Data.Typeable-import           Data.Word.Word24------------------------------------------------------------------------------------- | MySQL packet type----data Packet = Packet-    { pLen  :: !Int64-    , pSeqN :: !Word8-    , pBody :: !L.ByteString-    } deriving (Show, Eq)--putPacket :: Packet -> Put-putPacket (Packet len seqN body)  = do-    putWord24le (fromIntegral len)-    putWord8 seqN-    putLazyByteString body-{-# INLINE putPacket #-}--getPacket :: Get Packet-getPacket = do-    len <- fromIntegral <$> getWord24le-    seqN <- getWord8-    body <- getLazyByteString (fromIntegral len)-    return (Packet len seqN body)-{-# INLINE getPacket #-}--instance Binary Packet where-    put = putPacket-    {-# INLINE put #-}-    get = getPacket-    {-# INLINE get #-}--isERR :: Packet -> Bool-isERR p = L.index (pBody p) 0 == 0xFF-{-# INLINE isERR #-}--isOK :: Packet -> Bool-isOK p  = L.index (pBody p) 0 == 0x00-{-# INLINE isOK #-}--isEOF :: Packet -> Bool-isEOF p = L.index (pBody p) 0 == 0xFE-{-# INLINE isEOF #-}---- | Is there more packet to be read?------  https://dev.mysql.com/doc/internals/en/status-flags.html-isThereMore :: OK -> Bool-isThereMore p  = okStatus p .&. 0x08 /= 0-{-# INLINE isThereMore #-}---- | Decoding packet inside IO, throw 'DecodePacketException' on fail parsing,--- here we choose stability over correctness by omit incomplete consumed case:--- if we successful parse a packet, then we don't care if there're bytes left.----decodeFromPacket :: Binary a => Packet -> IO a-decodeFromPacket = getFromPacket get-{-# INLINE decodeFromPacket #-}--getFromPacket :: Get a -> Packet -> IO a-getFromPacket g (Packet _ _ body) = case parseDetailLazy g body of-    Left  (buf, offset, errmsg) -> throwIO (DecodePacketFailed buf offset errmsg)-    Right (_,   _,      r     ) -> return r-{-# INLINE getFromPacket #-}--data DecodePacketException = DecodePacketFailed ByteString ByteOffset String-  deriving (Typeable, Show)-instance Exception DecodePacketException--encodeToPacket :: Binary a => Word8 -> a -> Packet-encodeToPacket seqN payload =-    let s = encode payload-        l = L.length s-    in Packet (fromIntegral l) seqN s-{-# INLINE encodeToPacket #-}--putToPacket :: Word8 -> Put -> Packet-putToPacket seqN payload =-    let s = runPut payload-        l = L.length s-    in Packet (fromIntegral l) seqN s-{-# INLINE putToPacket #-}------------------------------------------------------------------------------------- OK, ERR, EOF---- | You may get interested in 'OK' packet because it provides information about--- successful operations.----data OK = OK-    { okAffectedRows :: !Int      -- ^ affected row number-    , okLastInsertID :: !Int      -- ^ last insert's ID-    , okStatus       :: !Word16-    , okWarningCnt   :: !Word16-    } deriving (Show, Eq)--getOK :: Get OK-getOK = OK <$ skipN 1-           <*> getLenEncInt-           <*> getLenEncInt-           <*> getWord16le-           <*> getWord16le-{-# INLINE getOK #-}--putOK :: OK -> Put-putOK (OK row lid stat wcnt) = do-    putWord8 0x00-    putLenEncInt row-    putLenEncInt lid-    putWord16le stat-    putWord16le wcnt-{-# INLINE putOK #-}--instance Binary OK where-    get = getOK-    {-# INLINE get #-}-    put = putOK-    {-# INLINE put #-}--data ERR = ERR-    { errCode  :: !Word16-    , errState :: !ByteString-    , errMsg   :: !ByteString-    } deriving (Show, Eq)--getERR :: Get ERR-getERR = ERR <$  skipN 1-             <*> getWord16le-             <*  skipN 1-             <*> getByteString 5-             <*> getRemainingByteString-{-# INLINE getERR #-}--putERR :: ERR -> Put-putERR (ERR code stat msg) = do-    putWord8 0xFF-    putWord16le code-    putWord8 35 -- '#'-    putByteString stat-    putByteString msg-{-# INLINE putERR #-}--instance Binary ERR where-    get = getERR-    {-# INLINE get #-}-    put = putERR-    {-# INLINE put #-}--data EOF = EOF-    { eofWarningCnt :: !Word16-    , eofStatus     :: !Word16-    } deriving (Show, Eq)--getEOF :: Get EOF-getEOF = EOF <$  skipN 1-             <*> getWord16le-             <*> getWord16le-{-# INLINE getEOF #-}--putEOF :: EOF -> Put-putEOF (EOF wcnt stat) = do-    putWord8 0xFE-    putWord16le wcnt-    putWord16le stat-{-# INLINE putEOF #-}--instance Binary EOF where-    get = getEOF-    {-# INLINE get #-}-    put = putEOF-    {-# INLINE put #-}-------------------------------------------------------------------------------------  Helpers--getByteStringNul :: Get ByteString-getByteStringNul = L.toStrict <$> getLazyByteStringNul-{-# INLINE getByteStringNul #-}--getRemainingByteString :: Get ByteString-getRemainingByteString = L.toStrict <$> getRemainingLazyByteString-{-# INLINE getRemainingByteString #-}--putLenEncBytes :: ByteString -> Put-putLenEncBytes c = do-    putLenEncInt (B.length c)-    putByteString c-{-# INLINE putLenEncBytes #-}--getLenEncBytes :: Get ByteString-getLenEncBytes = getLenEncInt >>= getByteString-{-# INLINE getLenEncBytes #-}---- | length encoded int--- https://dev.mysql.com/doc/internals/en/integer.html#packet-Protocol::LengthEncodedInteger-getLenEncInt:: Get Int-getLenEncInt = getWord8 >>= word2Len-  where-    word2Len l-         | l <  0xFB  = pure (fromIntegral l)-         | l == 0xFC  = fromIntegral <$> getWord16le-         | l == 0xFD  = fromIntegral <$> getWord24le-         | l == 0xFE  = fromIntegral <$> getWord64le-         | otherwise = fail $ "invalid length val " ++ show l-{-# INLINE getLenEncInt #-}--putLenEncInt:: Int -> Put-putLenEncInt x-         | x <  251      = putWord8 (fromIntegral x)-         | x < 65536     = putWord8 0xFC >> putWord16le (fromIntegral x)-         | x < 16777216  = putWord8 0xFD >> putWord24le (fromIntegral x)-         | otherwise     = putWord8 0xFE >> putWord64le (fromIntegral x)-{-# INLINE putLenEncInt #-}--putWord24le :: Word32 -> Put-putWord24le v = do-    putWord16le $ fromIntegral v-    putWord8 $ fromIntegral (v `shiftR` 16)-{-# INLINE putWord24le #-}--getWord24le :: Get Word32-getWord24le = do-    a <- fromIntegral <$> getWord16le-    b <- fromIntegral <$> getWord8-    return $! a .|. (b `shiftL` 16)-{-# INLINE getWord24le #-}--putWord48le :: Word64 -> Put-putWord48le v = do-    putWord32le $ fromIntegral v-    putWord16le $ fromIntegral (v `shiftR` 32)-{-# INLINE putWord48le #-}--getWord48le :: Get Word64-getWord48le = do-    a <- fromIntegral <$> getWord32le-    b <- fromIntegral <$> getWord16le-    return $! a .|. (b `shiftL` 32)-{-# INLINE getWord48le #-}--getWord24be :: Get Word24-getWord24be = do-    a <- fromIntegral <$> getWord16be-    b <- fromIntegral <$> getWord8-    return $! b .|. (a `shiftL` 8)-{-# INLINE getWord24be #-}--getInt24be :: Get Int24-getInt24be = do-    a <- fromIntegral <$> getWord16be-    b <- fromIntegral <$> getWord8-    return $! fromIntegral $ (b .|. (a `shiftL` 8) :: Word24)-{-# INLINE getInt24be #-}--getWord40be, getWord48be, getWord56be :: Get Word64-getWord40be = do-    a <- fromIntegral <$> getWord32be-    b <- fromIntegral <$> getWord8-    return $! (a `shiftL` 8) .|. b-getWord48be = do-    a <- fromIntegral <$> getWord32be-    b <- fromIntegral <$> getWord16be-    return $! (a `shiftL` 16) .|. b-getWord56be = do-    a <- fromIntegral <$> getWord32be-    b <- fromIntegral <$> getWord24be-    return $! (a `shiftL` 24) .|. b-{-# INLINE getWord40be #-}-{-# INLINE getWord48be #-}-{-# INLINE getWord56be #-}
− Database/MySQL/Query.hs
@@ -1,80 +0,0 @@-module Database.MySQL.Query where--import           Data.String               (IsString (..))-import           Control.Exception         (throw, Exception)-import           Data.Typeable-import qualified Data.ByteString.Lazy      as L-import qualified Data.ByteString.Lazy.Char8     as LC-import qualified Data.ByteString.Builder   as BB-import           Control.Arrow             (first)-import           Database.MySQL.Protocol.MySQLValue-import           Data.Binary.Put---- | Query string type borrowed from @mysql-simple@.------ This type is intended to make it difficult to--- construct a SQL query by concatenating string fragments, as that is--- an extremely common way to accidentally introduce SQL injection--- vulnerabilities into an application.------ This type is an instance of 'IsString', so the easiest way to--- construct a query is to enable the @OverloadedStrings@ language--- extension and then simply write the query in double quotes.------ The underlying type is a 'L.ByteString', and literal Haskell strings--- that contain Unicode characters will be correctly transformed to--- UTF-8.----newtype Query = Query { fromQuery :: L.ByteString } deriving (Eq, Ord, Typeable)--instance Show Query where-    show = show . fromQuery--instance Read Query where-    readsPrec i = fmap (first Query) . readsPrec i--instance IsString Query where-    fromString = Query . BB.toLazyByteString . BB.stringUtf8---- | A type to wrap a query parameter in to allow for single and multi-valued parameters.------ The behavior of 'Param' can be illustrated by following example:------ @---    render $ One (MySQLText "hello") = hello---    render $ Many [MySQLText "hello", MySQLText "world"] = hello, world---    render $ Many [] = null--- @------ So you can now write a query like this: @ SELECT * FROM test WHERE _id IN (?, 888) @--- and use 'Many' 'Param' to fill the hole. There's no equivalent for prepared statement sadly.----data Param = One  MySQLValue-           | Many [MySQLValue]---- | A type that may be used as a single parameter to a SQL query. Inspired from @mysql-simple@.-class QueryParam a where-    render :: a -> Put-    -- ^ Prepare a value for substitution into a query string.--instance QueryParam Param where-    render (One x)      = putTextField x-    render (Many [])    = putTextField MySQLNull-    render (Many (x:[]))= putTextField x-    render (Many (x:xs))= do putTextField x-                             mapM_ (\f -> putCharUtf8 ',' >> putTextField f) xs--instance QueryParam MySQLValue where-    render = putTextField--renderParams :: QueryParam p => Query -> [p] -> Query-renderParams (Query qry) params =-    let fragments = LC.split '?' qry-    in Query . runPut $ merge fragments params-  where-    merge [x]    []     = putLazyByteString x-    merge (x:xs) (y:ys) = putLazyByteString x >> render y >> merge xs ys-    merge _     _       = throw WrongParamsCount--data WrongParamsCount = WrongParamsCount deriving (Show, Typeable)-instance Exception WrongParamsCount
− Database/MySQL/TLS.hs
@@ -1,75 +0,0 @@-{-|-Module      : Database.MySQL.Connection-Description : TLS support for mysql-haskell via @tls@ package.-Copyright   : (c) Winterland, 2016-License     : BSD-Maintainer  : drkoster@qq.com-Stability   : experimental-Portability : PORTABLE--This module provides secure MySQL connection using 'tls' package, please make sure your certificate is v3 extension enabled.---}--module Database.MySQL.TLS (-      connect-    , connectDetail-    , module Data.TLSSetting-    ) where--import           Control.Exception              (bracketOnError, throwIO)-import qualified Data.Binary                    as Binary-import qualified Data.Binary.Put                as Binary-import qualified Data.Connection                as Conn-import           Data.IORef                     (newIORef)-import           Data.TLSSetting-import           Database.MySQL.Connection      hiding (connect, connectDetail)-import           Database.MySQL.Protocol.Auth-import           Database.MySQL.Protocol.Packet-import qualified Network.TLS                    as TLS-import qualified System.IO.Streams.TCP          as TCP-import qualified Data.Connection                as TCP-import qualified System.IO.Streams.TLS          as TLS-------------------------------------------------------------------------------------- | Provide a 'TLS.ClientParams' and a subject name to establish a TLS connection.----connect :: ConnectInfo -> (TLS.ClientParams, String) -> IO MySQLConn-connect c cp = fmap snd (connectDetail c cp)--connectDetail :: ConnectInfo -> (TLS.ClientParams, String) -> IO (Greeting, MySQLConn)-connectDetail (ConnectInfo host port db user pass charset) (cparams, subName) =-    bracketOnError (connectWithBufferSize host port bUFSIZE)-       (TCP.close) $ \ c -> do-            let is = TCP.source c-            is' <- decodeInputStream is-            p <- readPacket is'-            greet <- decodeFromPacket p-            if supportTLS (greetingCaps greet)-            then do-                let cparams' = cparams {-                            TLS.clientUseServerNameIndication = False-                        ,   TLS.clientServerIdentification = (subName, "")-                        }-                let (sock, sockAddr) = Conn.connExtraInfo c-                write c (encodeToPacket 1 $ sslRequest charset)-                bracketOnError (TLS.contextNew sock cparams')-                               ( \ ctx -> TLS.bye ctx >> TCP.close c ) $ \ ctx -> do-                    TLS.handshake ctx-                    tc <- TLS.tLsToConnection (ctx, sockAddr)-                    let tlsIs = TCP.source tc-                    tlsIs' <- decodeInputStream tlsIs-                    let auth = mkAuth db user pass charset greet-                    write tc (encodeToPacket 2 auth)-                    q <- readPacket tlsIs'-                    if isOK q-                    then do-                        consumed <- newIORef True-                        let conn = MySQLConn tlsIs' (write tc) (TCP.close tc) consumed-                        return (greet, conn)-                    else TCP.close c >> decodeFromPacket q >>= throwIO . ERRException-            else error "Database.MySQL.TLS: server doesn't support TLS connection"-  where-    connectWithBufferSize h p bs = TCP.connectSocket h p >>= TCP.socketToConnection bs-    write c a = TCP.send c $ Binary.runPut . Binary.put $ a
README.md view
@@ -2,20 +2,17 @@ =============  [![Hackage](https://img.shields.io/hackage/v/mysql-haskell.svg?style=flat)](http://hackage.haskell.org/package/mysql-haskell)-[![Build Status](https://travis-ci.org/winterland1989/mysql-haskell.svg)](https://travis-ci.org/winterland1989/mysql-haskell)  `mysql-haskell` is a MySQL driver written entirely in haskell. -<a href="http://www.genshuixue.com/"><img height=42 src='http://cdn.gsxservice.com/asset/img/logo-release2.png'></a> <a href="http://chordify.net/"><img height=42 src='https://chordify.net/img/about/slide_250_1.jpg'></a>-<a href="http://www.didichuxing.com/"><img height=42 src='http://www.didichuxing.com/images/icon02.png'></a>  Is it fast? ----------  In short, `select`(decode) is about 1.5 times slower than pure c/c++ but 5 times faster than `mysql-simple`, `insert` (encode) is about 1.5 times slower than pure c/c++, there're many factors involved(tls, prepared statment, batch using multiple statement): -<img src="https://github.com/winterland1989/mysql-haskell/blob/master/benchmark/result.png?raw=true" width="100%">+<img src="https://github.com/jappeace/mysql-pure/blob/master/benchmark/result.png?raw=true" width="100%">  Above figures showed the time to: @@ -35,7 +32,7 @@  + no replication protocol support. -`mysql-haskell` is intended to solve these problems, and provide foundation for higher level libraries such as groundhog and persistent, so that accessing MySQL is both fast and easy in haskell.+`mysql-pure` is intended to solve these problems, and provide foundation for higher level libraries such as groundhog and persistent, so that accessing MySQL is both fast and easy in haskell.  Guide -----@@ -106,8 +103,8 @@ Just use the old way:  ```bash-git clone https://github.com/winterland1989/mysql-haskell.git-cd mysql-haskell+git clone https://github.com/winterland1989/mysql-pure.git+cd mysql-pure cabal install --enable-tests --only-dependencies cabal build ```@@ -133,20 +130,10 @@  * Set `max_allowed_packet` to larger than 256M(for test large packet). -New features will be automatically tested by inspecting MySQL server's version, travis is keeping an eye on following combinations:--+ CABALVER=1.18 GHCVER=7.8.4  MYSQLVER=5.5-+ CABALVER=1.22 GHCVER=7.10.2 MYSQLVER=5.5-+ CABALVER=1.24 GHCVER=8.0.1  MYSQLVER=5.5-+ CABALVER=1.24 GHCVER=8.0.1  MYSQLVER=5.6-+ CABALVER=1.24 GHCVER=8.0.1  MYSQLVER=5.7--Please reference `.travis.yml` if you have problems with setting up test environment.--Enter benchmark directory and run `./bench.sh` to benchmark 1) c++ version 2) mysql-haskell 3) FFI version mysql, you may need to:+Enter benchmark directory and run `./bench.sh` to benchmark 1) c++ version 2) mysql-pure 3) FFI version mysql, you may need to:  + Modify `bench.sh`(change the include path) to get c++ version compiled.-+ Modify `mysql-haskell-bench.cabal`(change the openssl's lib path) to get haskell version compiled.++ Modify `mysql-pure-bench.cabal`(change the openssl's lib path) to get haskell version compiled. + Setup MySQL's TLS support, modify `MySQLHaskellOpenSSL.hs/MySQLHaskellTLS.hs` to change the CA file's path, and certificate's subject name. + Adjust rts options `-N` to get best results. @@ -155,7 +142,7 @@ Reference --------- -[MySQL official site](https://dev.mysql.com/doc/internals/en/) provided intensive document, but without following project, `mysql-haskell` may not be written at all:+[MySQL official site](https://dev.mysql.com/doc/internals/en/) provided intensive document, but without following project, `mysql-pure` may not be written at all:  + [mysql-binlog-connector-java](https://github.com/shyiko/mysql-binlog-connector-java) 
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
+ binary-parser-bench/Aeson.hs view
@@ -0,0 +1,361 @@+{-# LANGUAGE BangPatterns, CPP, OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-unused-binds #-}++module Aeson+    (+      aeson+    , aesonLazy+    , value'+    ) where++import Data.ByteString.Builder+  (Builder, byteString, toLazyByteString, charUtf8, word8)++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((*>), (<$>), (<*), pure)+import Data.Monoid (mappend, mempty)+#endif++import Control.Applicative (liftA2)+import Control.DeepSeq (NFData(..))+import Control.Monad (forM)+import Data.Attoparsec.ByteString.Char8 (Parser, char, endOfInput, scientific,+                                         skipSpace, string)+import Data.Bits ((.|.), shiftL)+import Data.ByteString (ByteString)+import Data.Char (chr)+import Data.List (sort)+import Data.Scientific (Scientific)+import Data.Text (Text)+import Data.Text.Encoding (decodeUtf8')+import Data.Vector as Vector (Vector, foldl', fromList)+import Data.Word (Word8)+import System.Directory (getDirectoryContents, doesDirectoryExist)+import System.FilePath ((</>), dropExtension)+import qualified Data.Attoparsec.ByteString as A+import qualified Data.Attoparsec.Lazy as L+import qualified Data.Attoparsec.Zepto as Z+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Unsafe as B+import qualified Data.HashMap.Strict as H+import Criterion.Main+import Common (pathTo)++#define BACKSLASH 92+#define CLOSE_CURLY 125+#define CLOSE_SQUARE 93+#define COMMA 44+#define DOUBLE_QUOTE 34+#define OPEN_CURLY 123+#define OPEN_SQUARE 91+#define C_0 48+#define C_9 57+#define C_A 65+#define C_F 70+#define C_a 97+#define C_f 102+#define C_n 110+#define C_t 116++data Result a = Error String+              | Success a+                deriving (Eq, Show)+++-- | A JSON \"object\" (key\/value map).+type Object = H.HashMap Text Value++-- | A JSON \"array\" (sequence).+type Array = Vector Value++-- | A JSON value represented as a Haskell value.+data Value = Object !Object+           | Array !Array+           | String !Text+           | Number !Scientific+           | Bool !Bool+           | Null+             deriving (Eq, Show)++instance NFData Value where+    rnf (Object o) = rnf o+    rnf (Array a)  = Vector.foldl' (\x y -> rnf y `seq` x) () a+    rnf (String s) = rnf s+    rnf (Number n) = rnf n+    rnf (Bool b)   = rnf b+    rnf Null       = ()++-- | Parse a top-level JSON value.  This must be either an object or+-- an array, per RFC 4627.+--+-- The conversion of a parsed value to a Haskell value is deferred+-- until the Haskell value is needed.  This may improve performance if+-- only a subset of the results of conversions are needed, but at a+-- cost in thunk allocation.+json :: Parser Value+json = json_ object_ array_++-- | Parse a top-level JSON value.  This must be either an object or+-- an array, per RFC 4627.+--+-- This is a strict version of 'json' which avoids building up thunks+-- during parsing; it performs all conversions immediately.  Prefer+-- this version if most of the JSON data needs to be accessed.+json' :: Parser Value+json' = json_ object_' array_'++json_ :: Parser Value -> Parser Value -> Parser Value+json_ obj ary = do+  w <- skipSpace *> A.satisfy (\w -> w == OPEN_CURLY || w == OPEN_SQUARE)+  if w == OPEN_CURLY+    then obj+    else ary+{-# INLINE json_ #-}++object_ :: Parser Value+object_ = {-# SCC "object_" #-} Object <$> objectValues jstring value++object_' :: Parser Value+object_' = {-# SCC "object_'" #-} do+  !vals <- objectValues jstring' value'+  return (Object vals)+ where+  jstring' = do+    !s <- jstring+    return s++objectValues :: Parser Text -> Parser Value -> Parser (H.HashMap Text Value)+objectValues str val = do+  skipSpace+  let pair = liftA2 (,) (str <* skipSpace) (char ':' *> skipSpace *> val)+  H.fromList <$> commaSeparated pair CLOSE_CURLY+{-# INLINE objectValues #-}++array_ :: Parser Value+array_ = {-# SCC "array_" #-} Array <$> arrayValues value++array_' :: Parser Value+array_' = {-# SCC "array_'" #-} do+  !vals <- arrayValues value'+  return (Array vals)++commaSeparated :: Parser a -> Word8 -> Parser [a]+commaSeparated item endByte = do+  w <- A.peekWord8'+  if w == endByte+    then A.anyWord8 >> return []+    else loop+  where+    loop = do+      v <- item <* skipSpace+      ch <- A.satisfy $ \w -> w == COMMA || w == endByte+      if ch == COMMA+        then skipSpace >> (v:) <$> loop+        else return [v]+{-# INLINE commaSeparated #-}++arrayValues :: Parser Value -> Parser (Vector Value)+arrayValues val = do+  skipSpace+  Vector.fromList <$> commaSeparated val CLOSE_SQUARE+{-# INLINE arrayValues #-}++-- | Parse any JSON value.  You should usually 'json' in preference to+-- this function, as this function relaxes the object-or-array+-- requirement of RFC 4627.+--+-- In particular, be careful in using this function if you think your+-- code might interoperate with Javascript.  A na&#xef;ve Javascript+-- library that parses JSON data using @eval@ is vulnerable to attack+-- unless the encoded data represents an object or an array.  JSON+-- implementations in other languages conform to that same restriction+-- to preserve interoperability and security.+value :: Parser Value+value = do+  w <- A.peekWord8'+  case w of+    DOUBLE_QUOTE  -> A.anyWord8 *> (String <$> jstring_)+    OPEN_CURLY    -> A.anyWord8 *> object_+    OPEN_SQUARE   -> A.anyWord8 *> array_+    C_f           -> string "false" *> pure (Bool False)+    C_t           -> string "true" *> pure (Bool True)+    C_n           -> string "null" *> pure Null+    _              | w >= 48 && w <= 57 || w == 45+                  -> Number <$> scientific+      | otherwise -> fail "not a valid json value"++-- | Strict version of 'value'. See also 'json''.+value' :: Parser Value+value' = do+  w <- A.peekWord8'+  case w of+    DOUBLE_QUOTE  -> do+                     !s <- A.anyWord8 *> jstring_+                     return (String s)+    OPEN_CURLY    -> A.anyWord8 *> object_'+    OPEN_SQUARE   -> A.anyWord8 *> array_'+    C_f           -> string "false" *> pure (Bool False)+    C_t           -> string "true" *> pure (Bool True)+    C_n           -> string "null" *> pure Null+    _              | w >= 48 && w <= 57 || w == 45+                  -> do+                     !n <- scientific+                     return (Number n)+      | otherwise -> fail "not a valid json value"++-- | Parse a quoted JSON string.+jstring :: Parser Text+jstring = A.word8 DOUBLE_QUOTE *> jstring_++-- | Parse a string without a leading quote.+jstring_ :: Parser Text+jstring_ = {-# SCC "jstring_" #-} do+  s <- A.scan False $ \s c -> if s then Just False+                                   else if c == DOUBLE_QUOTE+                                        then Nothing+                                        else Just (c == BACKSLASH)+  _ <- A.word8 DOUBLE_QUOTE+  s1 <- if BACKSLASH `B.elem` s+        then case Z.parse unescape s of+            Right r  -> return r+            Left err -> fail err+         else return s++  case decodeUtf8' s1 of+      Right r  -> return r+      Left err -> fail $ show err++{-# INLINE jstring_ #-}++unescape :: Z.Parser ByteString+unescape = toByteString <$> go mempty where+  go acc = do+    h <- Z.takeWhile (/=BACKSLASH)+    let rest = do+          start <- Z.take 2+          let !slash = B.unsafeHead start+              !t = B.unsafeIndex start 1+              escape = case B.findIndex (==t) "\"\\/ntbrfu" of+                         Just i -> i+                         _      -> 255+          if slash /= BACKSLASH || escape == 255+            then fail "invalid JSON escape sequence"+            else do+            let cont m = go (acc `mappend` byteString h `mappend` m)+                {-# INLINE cont #-}+            if t /= 117 -- 'u'+              then cont (word8 (B.unsafeIndex mapping escape))+              else do+                   a <- hexQuad+                   if a < 0xd800 || a > 0xdfff+                     then cont (charUtf8 (chr a))+                     else do+                       b <- Z.string "\\u" *> hexQuad+                       if a <= 0xdbff && b >= 0xdc00 && b <= 0xdfff+                         then let !c = ((a - 0xd800) `shiftL` 10) ++                                       (b - 0xdc00) + 0x10000+                              in cont (charUtf8 (chr c))+                         else fail "invalid UTF-16 surrogates"+    done <- Z.atEnd+    if done+      then return (acc `mappend` byteString h)+      else rest+  mapping = "\"\\/\n\t\b\r\f"++hexQuad :: Z.Parser Int+hexQuad = do+  s <- Z.take 4+  let hex n | w >= C_0 && w <= C_9 = w - C_0+            | w >= C_a && w <= C_f = w - 87+            | w >= C_A && w <= C_F = w - 55+            | otherwise          = 255+        where w = fromIntegral $ B.unsafeIndex s n+      a = hex 0; b = hex 1; c = hex 2; d = hex 3+  if (a .|. b .|. c .|. d) /= 255+    then return $! d .|. (c `shiftL` 4) .|. (b `shiftL` 8) .|. (a `shiftL` 12)+    else fail "invalid hex escape"++decodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString -> Maybe a+decodeWith p to s =+    case L.parse p s of+      L.Done _ v -> case to v of+                      Success a -> Just a+                      _         -> Nothing+      _          -> Nothing+{-# INLINE decodeWith #-}++decodeStrictWith :: Parser Value -> (Value -> Result a) -> B.ByteString+                 -> Maybe a+decodeStrictWith p to s =+    case either Error to (A.parseOnly p s) of+      Success a -> Just a+      Error _ -> Nothing+{-# INLINE decodeStrictWith #-}++eitherDecodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString+                 -> Either String a+eitherDecodeWith p to s =+    case L.parse p s of+      L.Done _ v -> case to v of+                      Success a -> Right a+                      Error msg -> Left msg+      L.Fail _ _ msg -> Left msg+{-# INLINE eitherDecodeWith #-}++eitherDecodeStrictWith :: Parser Value -> (Value -> Result a) -> B.ByteString+                       -> Either String a+eitherDecodeStrictWith p to s =+    case either Error to (A.parseOnly p s) of+      Success a -> Right a+      Error msg -> Left msg+{-# INLINE eitherDecodeStrictWith #-}++-- $lazy+--+-- The 'json' and 'value' parsers decouple identification from+-- conversion.  Identification occurs immediately (so that an invalid+-- JSON document can be rejected as early as possible), but conversion+-- to a Haskell value is deferred until that value is needed.+--+-- This decoupling can be time-efficient if only a smallish subset of+-- elements in a JSON value need to be inspected, since the cost of+-- conversion is zero for uninspected elements.  The trade off is an+-- increase in memory usage, due to allocation of thunks for values+-- that have not yet been converted.++-- $strict+--+-- The 'json'' and 'value'' parsers combine identification with+-- conversion.  They consume more CPU cycles up front, but have a+-- smaller memory footprint.++-- | Parse a top-level JSON value followed by optional whitespace and+-- end-of-input.  See also: 'json'.+jsonEOF :: Parser Value+jsonEOF = json <* skipSpace <* endOfInput++-- | Parse a top-level JSON value followed by optional whitespace and+-- end-of-input.  See also: 'json''.+jsonEOF' :: Parser Value+jsonEOF' = json' <* skipSpace <* endOfInput++toByteString :: Builder -> ByteString+toByteString = L.toStrict . toLazyByteString+{-# INLINE toByteString #-}++aeson :: IO [Benchmark]+aeson = do+  path <- pathTo "json-data"+  names <- sort . filter (`notElem` [".", ".."]) <$> getDirectoryContents path+  forM names $ \name -> do+    bs <- B.readFile (path </> name)+    return . bench ("attoparsec/" ++ dropExtension name) $ nf (A.parseOnly jsonEOF') bs++aesonLazy :: IO [Benchmark]+aesonLazy = do+  path <- pathTo "json-data"+  names <- sort . filter (`notElem` [".", ".."]) <$> getDirectoryContents path+  forM names $ \name -> do+    bs <- L.readFile (path </> name)+    return . bench ("attoparsec/lazy-bytestring/" ++ dropExtension name) $ nf (L.parse jsonEOF') bs
+ binary-parser-bench/AesonBP.hs view
@@ -0,0 +1,325 @@+{-# LANGUAGE BangPatterns, CPP, OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-unused-binds #-}++module AesonBP+    (+      aeson+    , aesonLazy+    , value'+    ) where++import Data.ByteString.Builder+  (Builder, byteString, toLazyByteString, charUtf8, word8)++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((*>), (<$>), (<*), pure)+import Data.Monoid (mappend, mempty)+#endif++import Control.Applicative (liftA2)+import Control.DeepSeq (NFData(..))+import Control.Monad (forM)+import Data.Bits ((.|.), shiftL)+import Data.ByteString (ByteString)+import Data.Char (chr)+import Data.List (sort)+import Data.Scientific (Scientific)+import Data.Text (Text)+import Data.Text.Encoding (decodeUtf8')+import Data.Vector as Vector (Vector, foldl', fromList)+import Data.Word (Word8)+import System.Directory (getDirectoryContents, doesDirectoryExist)+import System.FilePath ((</>), dropExtension)+import qualified Data.Attoparsec.Zepto as Z+import Data.Binary.Get (Get)+import qualified Data.Binary.Parser as BP+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Unsafe as B+import qualified Data.HashMap.Strict as H+import Criterion.Main+import Common (pathTo)++#define BACKSLASH 92+#define CLOSE_CURLY 125+#define CLOSE_SQUARE 93+#define COMMA 44+#define COLON 58+#define DOUBLE_QUOTE 34+#define OPEN_CURLY 123+#define OPEN_SQUARE 91+#define C_0 48+#define C_9 57+#define C_A 65+#define C_F 70+#define C_a 97+#define C_f 102+#define C_n 110+#define C_t 116++data Result a = Error String+              | Success a+                deriving (Eq, Show)+++-- | A JSON \"object\" (key\/value map).+type Object = H.HashMap Text Value++-- | A JSON \"array\" (sequence).+type Array = Vector Value++-- | A JSON value represented as a Haskell value.+data Value = Object !Object+           | Array !Array+           | String !Text+           | Number !Scientific+           | Bool !Bool+           | Null+             deriving (Eq, Show)++instance NFData Value where+    rnf (Object o) = rnf o+    rnf (Array a)  = Vector.foldl' (\x y -> rnf y `seq` x) () a+    rnf (String s) = rnf s+    rnf (Number n) = rnf n+    rnf (Bool b)   = rnf b+    rnf Null       = ()++-- | Parse a top-level JSON value.  This must be either an object or+-- an array, per RFC 4627.+--+-- The conversion of a parsed value to a Haskell value is deferred+-- until the Haskell value is needed.  This may improve performance if+-- only a subset of the results of conversions are needed, but at a+-- cost in thunk allocation.+json :: Get Value+json = json_ object_ array_++-- | Parse a top-level JSON value.  This must be either an object or+-- an array, per RFC 4627.+--+-- This is a strict version of 'json' which avoids building up thunks+-- during parsing; it performs all conversions immediately.  Prefer+-- this version if most of the JSON data needs to be accessed.+json' :: Get Value+json' = json_ object_' array_'++json_ :: Get Value -> Get Value -> Get Value+json_ obj ary = do+  w <- BP.skipSpaces *> BP.satisfy (\w -> w == OPEN_CURLY || w == OPEN_SQUARE)+  if w == OPEN_CURLY+    then obj+    else ary+{-# INLINE json_ #-}++object_ :: Get Value+object_ = {-# SCC "object_" #-} Object <$> objectValues jstring value++object_' :: Get Value+object_' = {-# SCC "object_'" #-} do+  !vals <- objectValues jstring' value'+  return (Object vals)+ where+  jstring' = do+    !s <- jstring+    return s++objectValues :: Get Text -> Get Value -> Get (H.HashMap Text Value)+objectValues str val = do+  BP.skipSpaces+  let pair = liftA2 (,) (str <* BP.skipSpaces) (BP.word8 COLON *> BP.skipSpaces *> val)+  H.fromList <$> commaSeparated pair CLOSE_CURLY+{-# INLINE objectValues #-}++array_ :: Get Value+array_ = {-# SCC "array_" #-} Array <$> arrayValues value++array_' :: Get Value+array_' = {-# SCC "array_'" #-} do+  !vals <- arrayValues value'+  return (Array vals)++commaSeparated :: Get a -> Word8 -> Get [a]+commaSeparated item endByte = do+  w <- BP.peek+  if w == endByte+    then BP.skipN 1 >> return []+    else loop+  where+    loop = do+      v <- item <* BP.skipSpaces+      ch <- BP.satisfy $ \w -> w == COMMA || w == endByte+      if ch == COMMA+        then BP.skipSpaces >> (v:) <$> loop+        else return [v]+{-# INLINE commaSeparated #-}++arrayValues :: Get Value -> Get (Vector Value)+arrayValues val = do+  BP.skipSpaces+  Vector.fromList <$> commaSeparated val CLOSE_SQUARE+{-# INLINE arrayValues #-}++-- | Parse any JSON value.  You should usually 'json' in preference to+-- this function, as this function relaxes the object-or-array+-- requirement of RFC 4627.+--+-- In particular, be careful in using this function if you think your+-- code might interoperate with Javascript.  A na&#xef;ve Javascript+-- library that parses JSON data using @eval@ is vulnerable to attack+-- unless the encoded data represents an object or an array.  JSON+-- implementations in other languages conform to that same restriction+-- to preserve interoperability and security.+value :: Get Value+value = do+  w <- BP.peek+  case w of+    DOUBLE_QUOTE  -> BP.skipN 1 *> (String <$> jstring_)+    OPEN_CURLY    -> BP.skipN 1 *> object_+    OPEN_SQUARE   -> BP.skipN 1 *> array_+    C_f           -> BP.string "false" *> pure (Bool False)+    C_t           -> BP.string "true" *> pure (Bool True)+    C_n           -> BP.string "null" *> pure Null+    _              | w >= 48 && w <= 57 || w == 45+                  -> Number <$> BP.scientific+      | otherwise -> fail "not a valid json value"++-- | Strict version of 'value'. See also 'json''.+value' :: Get Value+value' = do+  w <- BP.peek+  case w of+    DOUBLE_QUOTE  -> do+                     !s <- BP.skipN 1 *> jstring_+                     return (String s)+    OPEN_CURLY    -> BP.skipN 1 *> object_'+    OPEN_SQUARE   -> BP.skipN 1 *> array_'+    C_f           -> BP.string "false" *> pure (Bool False)+    C_t           -> BP.string "true" *> pure (Bool True)+    C_n           -> BP.string "null" *> pure Null+    _              | w >= 48 && w <= 57 || w == 45+                  -> do+                     !n <- BP.scientific+                     return (Number n)+      | otherwise -> fail "not a valid json value"++-- | Parse a quoted JSON string.+jstring :: Get Text+jstring = BP.word8 DOUBLE_QUOTE *> jstring_++-- | Parse a string without a leading quote.+jstring_ :: Get Text+jstring_ = {-# SCC "jstring_" #-} do+  s <- BP.scan False $ \s c -> if s then Just False+                                   else if c == DOUBLE_QUOTE+                                        then Nothing+                                        else Just (c == BACKSLASH)+  BP.word8 DOUBLE_QUOTE+  s1 <- if BACKSLASH `B.elem` s+        then case Z.parse unescape s of+            Right r  -> return r+            Left err -> fail err+         else return s++  case decodeUtf8' s1 of+      Right r  -> return r+      Left err -> fail $ show err++{-# INLINE jstring_ #-}++unescape :: Z.Parser ByteString+unescape = toByteString <$> go mempty where+  go acc = do+    h <- Z.takeWhile (/=BACKSLASH)+    let rest = do+          start <- Z.take 2+          let !slash = B.unsafeHead start+              !t = B.unsafeIndex start 1+              escape = case B.findIndex (==t) "\"\\/ntbrfu" of+                         Just i -> i+                         _      -> 255+          if slash /= BACKSLASH || escape == 255+            then fail "invalid JSON escape sequence"+            else do+            let cont m = go (acc `mappend` byteString h `mappend` m)+                {-# INLINE cont #-}+            if t /= 117 -- 'u'+              then cont (word8 (B.unsafeIndex mapping escape))+              else do+                   a <- hexQuad+                   if a < 0xd800 || a > 0xdfff+                     then cont (charUtf8 (chr a))+                     else do+                       b <- Z.string "\\u" *> hexQuad+                       if a <= 0xdbff && b >= 0xdc00 && b <= 0xdfff+                         then let !c = ((a - 0xd800) `shiftL` 10) ++                                       (b - 0xdc00) + 0x10000+                              in cont (charUtf8 (chr c))+                         else fail "invalid UTF-16 surrogates"+    done <- Z.atEnd+    if done+      then return (acc `mappend` byteString h)+      else rest+  mapping = "\"\\/\n\t\b\r\f"++hexQuad :: Z.Parser Int+hexQuad = do+  s <- Z.take 4+  let hex n | w >= C_0 && w <= C_9 = w - C_0+            | w >= C_a && w <= C_f = w - 87+            | w >= C_A && w <= C_F = w - 55+            | otherwise          = 255+        where w = fromIntegral $ B.unsafeIndex s n+      a = hex 0; b = hex 1; c = hex 2; d = hex 3+  if (a .|. b .|. c .|. d) /= 255+    then return $! d .|. (c `shiftL` 4) .|. (b `shiftL` 8) .|. (a `shiftL` 12)+    else fail "invalid hex escape"++-- $lazy+--+-- The 'json' and 'value' parsers decouple identification from+-- conversion.  Identification occurs immediately (so that an invalid+-- JSON document can be rejected as early as possible), but conversion+-- to a Haskell value is deferred until that value is needed.+--+-- This decoupling can be time-efficient if only a smallish subset of+-- elements in a JSON value need to be inspected, since the cost of+-- conversion is zero for uninspected elements.  The trade off is an+-- increase in memory usage, due to allocation of thunks for values+-- that have not yet been converted.++-- $strict+--+-- The 'json'' and 'value'' parsers combine identification with+-- conversion.  They consume more CPU cycles up front, but have a+-- smaller memory footprint.++-- | Parse a top-level JSON value followed by optional whitespace and+-- end-of-input.  See also: 'json'.+jsonEOF :: Get Value+jsonEOF = json <* BP.skipSpaces++-- | Parse a top-level JSON value followed by optional whitespace and+-- end-of-input.  See also: 'json''.+jsonEOF' :: Get Value+jsonEOF' = json' <* BP.skipSpaces++toByteString :: Builder -> ByteString+toByteString = L.toStrict . toLazyByteString+{-# INLINE toByteString #-}++aeson :: IO [Benchmark]+aeson = do+  path <- pathTo "json-data"+  names <- sort . filter (`notElem` [".", ".."]) <$> getDirectoryContents path+  forM names $ \name -> do+    bs <- B.readFile (path </> name)+    return . bench ("binary-parser/" ++ dropExtension name) $ nf (BP.parseOnly jsonEOF') bs++aesonLazy :: IO [Benchmark]+aesonLazy = do+  path <- pathTo "json-data"+  names <- sort . filter (`notElem` [".", ".."]) <$> getDirectoryContents path+  forM names $ \name -> do+    bs <- L.readFile (path </> name)+    return . bench ("binary-parser/lazy-bytestring/" ++ dropExtension name) $ nf (BP.parseLazy jsonEOF') bs
+ binary-parser-bench/Bench.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE OverloadedStrings #-}++module Main (main) where++import Criterion.Main+import qualified Aeson+import qualified AesonBP+import qualified HttpReq+import Data.List++main :: IO ()+main = do+    http <- HttpReq.headers++    putStrLn "start benchmark http request parser"++    defaultMain http++    putStrLn "start benchmark JSON parser"++    aeson <- Aeson.aeson+    aesonbp <- AesonBP.aeson+    aesonLazy <- Aeson.aesonLazy+    aesonbpLazy <- AesonBP.aesonLazy++    (defaultMain . concat . transpose) [ aeson, aesonbp, aesonLazy, aesonbpLazy ]
+ binary-parser-bench/Common.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Common (+      chunksOf+    , pathTo+    , rechunkBS+    , rechunkT+    ) where++import Control.DeepSeq (NFData(rnf))+import System.Directory (doesDirectoryExist)+import System.FilePath ((</>))+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL++#if !MIN_VERSION_bytestring(0,10,0)+import Data.ByteString.Internal (ByteString(..))++instance NFData ByteString where+    rnf (PS _ _ _) = ()+#endif++chunksOf :: Int -> [a] -> [[a]]+chunksOf k = go+  where go xs = case splitAt k xs of+                  ([],_)  -> []+                  (y, ys) -> y : go ys++rechunkBS :: Int -> B.ByteString -> BL.ByteString+rechunkBS n = BL.fromChunks . map B.pack . chunksOf n . B.unpack++rechunkT :: Int -> T.Text -> TL.Text+rechunkT n = TL.fromChunks . map T.pack . chunksOf n . T.unpack++pathTo :: String -> IO FilePath+pathTo wat = do+  exists <- doesDirectoryExist "bench"+  return $ if exists+           then "bench" </> wat+           else wat
+ binary-parser-bench/HttpReq.hs view
@@ -0,0 +1,134 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+module HttpReq (headers) where++import Common (pathTo, rechunkBS)+import Control.Applicative+import Criterion.Main (bench, bgroup, nf, nfIO)+import Control.DeepSeq (NFData(..))+import Criterion.Types (Benchmark)+import Network.Wai.Handler.Warp.RequestHeader (parseHeaderLines)+import Data.ByteString.Internal (c2w, w2c)+import qualified Data.Attoparsec.ByteString as AP+import qualified Data.Attoparsec.ByteString.Char8 as APC+import qualified Data.ByteString.Char8 as BC+import qualified Data.Binary.Parser as BP+import Network.HTTP.Types.Version (HttpVersion, http11)+import qualified Scanner as SC++headers :: IO [Benchmark]+headers = do+  req <- BC.readFile =<< pathTo "http-request.txt"+  return [+        bench "http-req/attoparsec" $ nf (AP.parseOnly attoRequest) req+      , bench "http-req/binary-parsers" $ nf (BP.parseOnly bpRequest) req+      , bench "http-req/scanner" $ nf (SC.scanOnly scRequest) req+      , bench "http-req/warp" $ nfIO (parseHeaderLines (BC.lines req))+      ]++--------------------------------------------------------------------------------++instance NFData HttpVersion where+    rnf !_ = ()++attoHeader = do+  name <- APC.takeWhile1 (APC.inClass "a-zA-Z0-9_-") <* APC.char ':' <* APC.skipSpace+  body <- attoBodyLine+  return (name, body)++attoBodyLine = APC.takeTill (\c -> c == '\r' || c == '\n') <* APC.endOfLine++attoReqLine = do+  m <- (APC.takeTill APC.isSpace <* APC.char ' ')+  (p,q) <- BC.break (=='?') <$> (APC.takeTill APC.isSpace <* APC.char ' ')+  v <- attoHttpVersion+  return (m,p,q,v)++attoHttpVersion = http11 <$ APC.string "HTTP/1.1"++attoRequest = (,) <$> (attoReqLine <* APC.endOfLine) <*> attoManyHeader++attoManyHeader = do+  c <- APC.peekChar'+  if c == '\r' || c == '\n'+    then return []++    else (:) <$> attoHeader <*> attoManyHeader++--------------------------------------------------------------------------------++bpHeader = do+  name <- BP.takeWhile1 isHeaderWord8 <* BP.word8 (c2w ':') <* BP.skipSpaces+  body <- bpBodyLine+  return (name, body)+  where+    isHeaderWord8 w = let c = w2c w in+                   ('a' <= c && c <= 'z')+                || ('A' <= c && c <= 'Z')+                || ('0' <= c && c <= '0')+                || c == '_' || c == '-'++bpBodyLine = BP.takeTill (\w -> w == 13 || w == 10) <* BP.endOfLine++bpReqLine = do+  m <- (BP.takeTill BP.isSpace <* BP.word8 (c2w ' '))+  (p,q) <- BC.break (=='?') <$> (BP.takeTill BP.isSpace <* BP.word8 (c2w ' '))+  v <- bpHttpVersion+  return (m,p,q,v)++bpHttpVersion = http11 <$ BP.string "HTTP/1.1"++bpRequest = (,) <$> (bpReqLine <* BP.endOfLine) <*> bpManyHeader++bpManyHeader = do+  w <- BP.peek+  let c = w2c w+  if c == '\r' || c == '\n'+    then return []+    else (:) <$> bpHeader <*> bpManyHeader++--------------------------------------------------------------------------------++scHeader = do+  name <- takeWhile1 (isHeaderChar . w2c) <* SC.char8 ':' <* SC.skipSpace+  body <- scBodyLine+  return (name, body)+  where+    isHeaderChar c = ('a' <= c && c <= 'z')+                  || ('A' <= c && c <= 'Z')+                  || ('0' <= c && c <= '0')+                  || c == '_' || c == '-'++    takeWhile1 p = do+        bs <- SC.takeWhile p+        if BC.null bs then fail "takeWhile1" else return bs++scEndOfLine = do        -- scanner doesn't provide endOfLine, so we roll one here+    w <- SC.anyWord8+    case w of+        10 -> return ()+        13 -> SC.word8 10+        _  -> fail "endOfLine"+{-# INLINE scEndOfLine #-}++scBodyLine = SC.takeWhile (\w -> let c = w2c w in c /= '\r' && c /= '\n') <* scEndOfLine++scReqLine = do+  m <- (SC.takeWhile (not . BP.isSpace) <* SC.char8 ' ')+  (p,q) <- BC.break (=='?') <$> (SC.takeWhile (not . BP.isSpace) <* SC.char8 ' ')+  v <- scHttpVersion+  return (m,p,q,v)++scHttpVersion = http11 <$ SC.string "HTTP/1.1"++scRequest = (,) <$> (scReqLine <* scEndOfLine) <*> scManyHeader++scManyHeader = do+  w <- SC.lookAhead+  case w of+    Just w' -> do+      let c = w2c w'+      if c == '\r' || c == '\n'+        then return []+        else (:) <$> scHeader <*> scManyHeader+    _ -> fail "scManyHeader"
+ binary-parser-bench/Network/Wai/Handler/Warp/ReadInt.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE BangPatterns #-}++-- Copyright     : Erik de Castro Lopo <erikd@mega-nerd.com>+-- License       : BSD3++module Network.Wai.Handler.Warp.ReadInt (+    readInt+  , readInt64+  ) where++-- This function lives in its own file because the MagicHash pragma interacts+-- poorly with the CPP pragma.++import Data.ByteString (ByteString)+import qualified Data.ByteString as S+import Data.Int (Int64)+import GHC.Exts (Addr#, Int(..), indexWord8OffAddr#, word2Int#, word8ToWord#)+import GHC.Word++{-# INLINE readInt #-}+readInt :: Integral a => ByteString -> a+readInt bs = fromIntegral $ readInt64 bs++-- This function is used to parse the Content-Length field of HTTP headers and+-- is a performance hot spot. It should only be replaced with something+-- significantly and provably faster.+--+-- It needs to be able work correctly on 32 bit CPUs for file sizes > 2G so we+-- use Int64 here and then make a generic 'readInt' that allows conversion to+-- Int and Integer.++{-# NOINLINE readInt64 #-}+readInt64 :: ByteString -> Int64+readInt64 bs = S.foldl' (\ !i !c -> i * 10 + fromIntegral (mhDigitToInt c)) 0+             $ S.takeWhile isDigit bs++data Table = Table !Addr#++{-# NOINLINE mhDigitToInt #-}+mhDigitToInt :: Word8 -> Int+mhDigitToInt (W8# i) = I# (word2Int# (word8ToWord# (indexWord8OffAddr# addr (word2Int# (word8ToWord# i)))))+  where+    !(Table addr) = table+    table :: Table+    table = Table+        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+        \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#++isDigit :: Word8 -> Bool+isDigit w = w >= 48 && w <= 57
+ binary-parser-bench/Network/Wai/Handler/Warp/RequestHeader.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BangPatterns #-}++module Network.Wai.Handler.Warp.RequestHeader (+      parseHeaderLines+    , parseByteRanges+    ) where++import Control.Exception (Exception, throwIO)+import Control.Monad (when)+import Data.Typeable (Typeable)+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as B (unpack, readInteger)+import Data.ByteString.Internal (ByteString(..), memchr)+import qualified Data.CaseInsensitive as CI+import Data.Word (Word8)+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Ptr (Ptr, plusPtr, minusPtr, nullPtr)+import Foreign.Storable (peek)+import qualified Network.HTTP.Types as H+-- import Network.Wai.Handler.Warp.Types+import qualified Network.HTTP.Types.Header as HH+-- $setup+-- >>> :set -XOverloadedStrings++data InvalidRequest = NotEnoughLines [String]+                    | BadFirstLine String+                    | NonHttp+                    | IncompleteHeaders+                    | ConnectionClosedByPeer+                    | OverLargeHeader+                    deriving (Eq, Typeable, Show)++instance Exception InvalidRequest++----------------------------------------------------------------++parseHeaderLines :: [ByteString]+                 -> IO (H.Method+                       ,ByteString  --  Path+                       ,ByteString  --  Path, parsed+                       ,ByteString  --  Query+                       ,H.HttpVersion+                       ,H.RequestHeaders+                       )+parseHeaderLines [] = throwIO $ NotEnoughLines []+parseHeaderLines (firstLine:otherLines) = do+    (method, path', query, httpversion) <- parseRequestLine firstLine+    let path = H.extractPath path'+        hdr = map parseHeader otherLines+    return (method, path', path, query, httpversion, hdr)++----------------------------------------------------------------++-- |+--+-- >>> parseRequestLine "GET / HTTP/1.1"+-- ("GET","/","",HTTP/1.1)+-- >>> parseRequestLine "POST /cgi/search.cgi?key=foo HTTP/1.0"+-- ("POST","/cgi/search.cgi","?key=foo",HTTP/1.0)+-- >>> parseRequestLine "GET "+-- *** Exception: Warp: Invalid first line of request: "GET "+-- >>> parseRequestLine "GET /NotHTTP UNKNOWN/1.1"+-- *** Exception: Warp: Request line specified a non-HTTP request+parseRequestLine :: ByteString+                 -> IO (H.Method+                       ,ByteString -- Path+                       ,ByteString -- Query+                       ,H.HttpVersion)+parseRequestLine requestLine@(PS fptr off len) = withForeignPtr fptr $ \ptr -> do+    when (len < 14) $ throwIO baderr+    let methodptr = ptr `plusPtr` off+        limptr = methodptr `plusPtr` len+        lim0 = fromIntegral len++    pathptr0 <- memchr methodptr 32 lim0 -- ' '+    when (pathptr0 == nullPtr || (limptr `minusPtr` pathptr0) < 11) $+        throwIO baderr+    let pathptr = pathptr0 `plusPtr` 1+        lim1 = fromIntegral (limptr `minusPtr` pathptr0)++    httpptr0 <- memchr pathptr 32 lim1 -- ' '+    when (httpptr0 == nullPtr || (limptr `minusPtr` httpptr0) < 9) $+        throwIO baderr+    let httpptr = httpptr0 `plusPtr` 1+        lim2 = fromIntegral (httpptr0 `minusPtr` pathptr)++    checkHTTP httpptr+    !hv <- httpVersion httpptr+    queryptr <- memchr pathptr 63 lim2 -- '?'++    let !method = bs ptr methodptr pathptr0+        !path+          | queryptr == nullPtr = bs ptr pathptr httpptr0+          | otherwise           = bs ptr pathptr queryptr+        !query+          | queryptr == nullPtr = S.empty+          | otherwise           = bs ptr queryptr httpptr0++    return (method,path,query,hv)+  where+    baderr = BadFirstLine $ B.unpack requestLine+    check :: Ptr Word8 -> Int -> Word8 -> IO ()+    check p n w = do+        w0 <- peek $ p `plusPtr` n+        when (w0 /= w) $ throwIO NonHttp+    checkHTTP httpptr = do+        check httpptr 0 72 -- 'H'+        check httpptr 1 84 -- 'T'+        check httpptr 2 84 -- 'T'+        check httpptr 3 80 -- 'P'+        check httpptr 4 47 -- '/'+        check httpptr 6 46 -- '.'+    httpVersion httpptr = do+        major <- peek $ httpptr `plusPtr` 5+        minor <- peek $ httpptr `plusPtr` 7+        return $ if major == (49 :: Word8) && minor == (49 :: Word8) then+            H.http11+          else+            H.http10+    bs ptr p0 p1 = PS fptr o l+      where+        o = p0 `minusPtr` ptr+        l = p1 `minusPtr` p0++----------------------------------------------------------------++-- |+--+-- >>> parseHeader "Content-Length:47"+-- ("Content-Length","47")+-- >>> parseHeader "Accept-Ranges: bytes"+-- ("Accept-Ranges","bytes")+-- >>> parseHeader "Host:  example.com:8080"+-- ("Host","example.com:8080")+-- >>> parseHeader "NoSemiColon"+-- ("NoSemiColon","")++parseHeader :: ByteString -> H.Header+parseHeader s =+    let (k, rest) = S.break (== 58) s -- ':'+        rest' = S.dropWhile (\c -> c == 32 || c == 9) $ S.drop 1 rest+     in (CI.mk k, rest')++parseByteRanges :: S.ByteString -> Maybe HH.ByteRanges+parseByteRanges bs1 = do+    bs2 <- stripPrefix "bytes=" bs1+    (r, bs3) <- range bs2+    ranges (r:) bs3+  where+    range bs2 =+        case stripPrefix "-" bs2 of+            Just bs3 -> do+                (i, bs4) <- B.readInteger bs3+                Just (HH.ByteRangeSuffix i, bs4)+            Nothing -> do+                (i, bs3) <- B.readInteger bs2+                bs4 <- stripPrefix "-" bs3+                case B.readInteger bs4 of+                    Nothing -> Just (HH.ByteRangeFrom i, bs4)+                    Just (j, bs5) -> Just (HH.ByteRangeFromTo i j, bs5)+    ranges front bs3 =+        case stripPrefix "," bs3 of+            Nothing -> Just (front [])+            Just bs4 -> do+                (r, bs5) <- range bs4+                ranges (front . (r:)) bs5++    stripPrefix x y+        | x `S.isPrefixOf` y = Just (S.drop (S.length x) y)+        | otherwise = Nothing
+ mozillaCAStore.pem view
@@ -0,0 +1,3955 @@+##+## Bundle of CA Root Certificates+##+## Certificate data from Mozilla as of: Wed Jun  7 03:12:05 2017 GMT+##+## This is a bundle of X.509 certificates of public Certificate Authorities+## (CA). These were automatically extracted from Mozilla's root certificates+## file (certdata.txt).  This file can be found in the mozilla source tree:+## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt+##+## It contains the certificates in PEM format and therefore+## can be directly used with curl / libcurl / php_curl, or with+## an Apache+mod_ssl webserver for SSL client authentication.+## Just configure this file as the SSLCACertificateFile.+##+## Conversion done with mk-ca-bundle.pl version 1.27.+## SHA256: 93753268e1c596aee21893fb1c6975338389132f15c942ed65fc394a904371d7+##+++GlobalSign Root CA+==================+-----BEGIN CERTIFICATE-----+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx+GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds+b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV+BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD+VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa+DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc+THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb+Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP+c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX+gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF+AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj+Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG+j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH+hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC+X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==+-----END CERTIFICATE-----++GlobalSign Root CA - R2+=======================+-----BEGIN CERTIFICATE-----+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv+YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh+bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT+aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6+ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp+s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN+S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL+TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C+ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E+FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i+YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN+BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp+9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu+01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7+9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==+-----END CERTIFICATE-----++Verisign Class 3 Public Primary Certification Authority - G3+============================================================+-----BEGIN CERTIFICATE-----+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC+ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1+EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc+cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw+EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj+055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA+ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f+j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0+xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa+t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==+-----END CERTIFICATE-----++Entrust.net Premium 2048 Secure Server CA+=========================================+-----BEGIN CERTIFICATE-----+MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u+ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp+bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV+BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx+NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3+d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u+ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A+MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL+Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr+hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW+nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi+VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ+KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy+T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf+zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT+J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e+nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=+-----END CERTIFICATE-----++Baltimore CyberTrust Root+=========================+-----BEGIN CERTIFICATE-----+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE+ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li+ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC+SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs+dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME+uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB+UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C+G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9+XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr+l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI+VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB+BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh+cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5+hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa+Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H+RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp+-----END CERTIFICATE-----++AddTrust Low-Value Services Root+================================+-----BEGIN CERTIFICATE-----+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU+cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw+CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO+ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB+AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6+54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr+oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1+Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui+GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w+HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD+AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT+RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw+HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt+ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph+iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr+mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj+ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=+-----END CERTIFICATE-----++AddTrust External Root+======================+-----BEGIN CERTIFICATE-----+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML+QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD+VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw+NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU+cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg+Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw+Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo+aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy+2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7+7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL+VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk+VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl+j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355+e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u+G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=+-----END CERTIFICATE-----++AddTrust Public Services Root+=============================+-----BEGIN CERTIFICATE-----+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU+cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ+BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l+dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF+AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu+nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i+d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG+Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw+HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G+A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB+/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux+FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G+A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4+JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9+Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H+EufOX1362KqxMy3ZdvJOOjMMK7MtkAY=+-----END CERTIFICATE-----++AddTrust Qualified Certificates Root+====================================+-----BEGIN CERTIFICATE-----+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU+cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx+CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ+IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx+64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3+KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o+L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR+wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU+MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/+BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE+BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y+azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD+ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG+GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze+RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB+iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=+-----END CERTIFICATE-----++Entrust Root Certification Authority+====================================+-----BEGIN CERTIFICATE-----+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV+BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw+b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG+A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0+MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu+MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu+Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v+dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB+ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz+A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww+Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68+j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN+rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw+DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1+MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH+hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM+Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa+v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS+W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0+tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8+-----END CERTIFICATE-----++GeoTrust Global CA+==================+-----BEGIN CERTIFICATE-----+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK+Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw+MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j+LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB+CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo+BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet+8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc+T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU+vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD+AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk+DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q+zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4+d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2+mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p+XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm+Mw==+-----END CERTIFICATE-----++GeoTrust Global CA 2+====================+-----BEGIN CERTIFICATE-----+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN+R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw+MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j+LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw+ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/+NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k+LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA+Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b+HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF+MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH+K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7+srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh+ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL+OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC+x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF+H4z1Ir+rzoPz4iIprn2DQKi6bA==+-----END CERTIFICATE-----++GeoTrust Universal CA+=====================+-----BEGIN CERTIFICATE-----+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN+R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1+MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu+Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP+ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t+JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e+RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs+7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d+8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V+qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga+Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB+Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu+KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08+ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0+XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB+hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2+qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL+oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK+xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF+KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2+DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK+xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU+p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI+P/rmMuGNG2+k5o7Y+SlIis5z/iw=+-----END CERTIFICATE-----++GeoTrust Universal CA 2+=======================+-----BEGIN CERTIFICATE-----+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN+R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0+MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg+SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA+A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0+DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17+j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q+JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a+QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2+WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP+20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn+ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC+SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG+8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E+BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ+4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr++mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq+A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg+Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP+pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d+FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp+gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm+X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS+-----END CERTIFICATE-----++Visa eCommerce Root+===================+-----BEGIN CERTIFICATE-----+MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG+EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug+QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2+WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm+VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv+bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL+F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b+RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0+TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI+/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs+GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG+MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc+CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW+YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz+zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu+YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt+398znM/jra6O1I7mT1GvFpLgXPYHDw==+-----END CERTIFICATE-----++Certum Root CA+==============+-----BEGIN CERTIFICATE-----+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK+ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla+Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u+by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x+wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL+kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ+89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K+Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P+NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq+hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze++GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg+GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/+0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS+qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==+-----END CERTIFICATE-----++Comodo AAA Services root+========================+-----BEGIN CERTIFICATE-----+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg+TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw+MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl+c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV+BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC+ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG+C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs+i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW+Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH+Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK+Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f+BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl+cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz+LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm+7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z+8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C+12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==+-----END CERTIFICATE-----++Comodo Secure Services root+===========================+-----BEGIN CERTIFICATE-----+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg+TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw+MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu+Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi+BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP+ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP+9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc+rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC+oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V+p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E+FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w+gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj+YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm+aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm+4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL+DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw+pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H+RR3B7Hzs/Sk=+-----END CERTIFICATE-----++Comodo Trusted Services root+============================+-----BEGIN CERTIFICATE-----+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg+TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw+MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h+bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw+IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC+AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7+3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y+/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6+juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS+ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud+DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB+/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp+ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl+cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw+uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA+BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l+R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O+9y5Xt5hwXsjEeLBi+-----END CERTIFICATE-----++QuoVadis Root CA+================+-----BEGIN CERTIFICATE-----+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE+ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0+eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz+MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp+cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD+EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF+AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk+J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL+F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL+YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen+AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w+PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y+ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7+MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj+YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs+ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW+Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu+BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw+FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0+aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6+tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo+fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul+LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x+gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi+5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi+5nrQNiOKSnQ2+Q==+-----END CERTIFICATE-----++QuoVadis Root CA 2+==================+-----BEGIN CERTIFICATE-----+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx+ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC+DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6+XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk+lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB+lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy+lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt+66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn+wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh+D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy+BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie+J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud+DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU+a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv+Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3+UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm+VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW+IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1+WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X+f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II+4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8+VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u+-----END CERTIFICATE-----++QuoVadis Root CA 3+==================+-----BEGIN CERTIFICATE-----+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx+OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC+DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg+DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij+KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K+DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv+BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp+p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8+nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX+MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM+Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz+uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT+BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj+YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB+BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD+VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4+ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE+AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV+qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s+hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z+POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2+Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp+8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC+bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu+g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p+vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr+qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=+-----END CERTIFICATE-----++Security Communication Root CA+==============================+-----BEGIN CERTIFICATE-----+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw+HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw+8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM+DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX+5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd+DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2+JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw+DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g+0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a+mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ+s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ+6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi+FL39vmwLAw==+-----END CERTIFICATE-----++Sonera Class 2 Root CA+======================+-----BEGIN CERTIFICATE-----+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG+U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw+NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh+IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3+/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT+dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG+f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P+tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH+nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT+XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt+0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI+cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph+Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx+EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH+llpwrN9M+-----END CERTIFICATE-----++UTN USERFirst Hardware Root CA+==============================+-----BEGIN CERTIFICATE-----+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd+BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx+OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0+eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz+ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3+DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI+wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd+tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8+i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf+Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw+gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF+lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF+UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF+BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW+XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2+lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn+iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67+nfhmqA==+-----END CERTIFICATE-----++Camerfirma Chambers of Commerce Root+====================================+-----BEGIN CERTIFICATE-----+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i+ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx+NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp+cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn+MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC+AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU+xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH+NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW+DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV+d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud+EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v+cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P+AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh+bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD+VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi+fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD+L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN+UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n+ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1+erfutGWaIZDgqtCYvDi1czyL+Nw=+-----END CERTIFICATE-----++Camerfirma Global Chambersign Root+==================================+-----BEGIN CERTIFICATE-----+MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i+ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx+NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt+YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg+MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw+ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J+1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O+by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl+6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c+8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/+BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j+aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B+Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj+aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y+ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh+bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA+PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y+gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ+PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4+IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes+t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==+-----END CERTIFICATE-----++XRamp Global CA Root+====================+-----BEGIN CERTIFICATE-----+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE+BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj+dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB+dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx+HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg+U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp+dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu+IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx+foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE+zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs+AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry+xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap+oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC+AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc+/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n+nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz+8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=+-----END CERTIFICATE-----++Go Daddy Class 2 CA+===================+-----BEGIN CERTIFICATE-----+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY+VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp+ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG+A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g+RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD+ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv+2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32+qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j+YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY+vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O+BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o+atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu+MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim+PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt+I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI+Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b+vZ8=+-----END CERTIFICATE-----++Starfield Class 2 CA+====================+-----BEGIN CERTIFICATE-----+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc+U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo+MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG+A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG+SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY+bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ+JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm+epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN+F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF+MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f+hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo+bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g+QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs+afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM+PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD+KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3+QBFGmh95DmK/D5fs4C8fF5Q=+-----END CERTIFICATE-----++StartCom Certification Authority+================================+-----BEGIN CERTIFICATE-----+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0+NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT+37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0+Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj+YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH+AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw+Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg+U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5+LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl+cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh+cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT+dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC+AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh+3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm+vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk+fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3+fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ+EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl+1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/+lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro+g14=+-----END CERTIFICATE-----++Taiwan GRCA+===========+-----BEGIN CERTIFICATE-----+MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG+EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X+DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv+dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD+ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN+w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5+BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O+1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO+htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov+J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7+Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t+B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB+O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8+lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV+HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2+09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ+TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj+Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2+Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU+D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz+DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk+Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk+7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ+CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS+-----END CERTIFICATE-----++Swisscom Root CA 1+==================+-----BEGIN CERTIFICATE-----+MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG+EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy+dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4+MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln+aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM+MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF+NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe+AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC+b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn+7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN+cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp+WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5+haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY+MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw+HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j+BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9+MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn+jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ+MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H+VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl+vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl+OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3+1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq+nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy+x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW+NY6E0F/6MBr1mmz0DlP5OlvRHA==+-----END CERTIFICATE-----++DigiCert Assured ID Root CA+===========================+-----BEGIN CERTIFICATE-----+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx+MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO+9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy+UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW+/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy+oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf+GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF+66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq+hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc+EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn+SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i+8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==+-----END CERTIFICATE-----++DigiCert Global Root CA+=======================+-----BEGIN CERTIFICATE-----+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw+MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn+TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5+BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H+4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y+7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB+o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm+8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF+BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr+EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt+tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886+UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=+-----END CERTIFICATE-----++DigiCert High Assurance EV Root CA+==================================+-----BEGIN CERTIFICATE-----+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw+KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw+MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ+MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu+Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t+Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS+OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3+MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ+NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe+h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB+Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY+JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ+V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp+myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK+mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K+-----END CERTIFICATE-----++Certplus Class 2 Primary CA+===========================+-----BEGIN CERTIFICATE-----+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE+BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN+OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy+dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP+ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR+5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ+Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO+YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e+e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME+CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ+YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t+L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD+P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R+TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/++7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW+//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7+l7+ijrRU+-----END CERTIFICATE-----++DST Root CA X3+==============+-----BEGIN CERTIFICATE-----+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK+ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X+DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1+cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD+ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT+rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9+UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy+xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d+utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ+MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug+dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE+GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw+RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS+fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ+-----END CERTIFICATE-----++DST ACES CA X6+==============+-----BEGIN CERTIFICATE-----+MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG+EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT+MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha+MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE+CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC+AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI+DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa+pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow+GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy+MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu+Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy+dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU+CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2+5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t+Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq+nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs+vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3+oKfN5XozNmr6mis=+-----END CERTIFICATE-----++SwissSign Gold CA - G2+======================+-----BEGIN CERTIFICATE-----+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw+EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN+MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp+c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B+AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq+t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C+jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg+vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF+ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR+AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend+jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO+peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR+7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi+GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw+AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64+OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm+5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr+44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf+Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m+Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp+mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk+vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf+KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br+NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj+viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ+-----END CERTIFICATE-----++SwissSign Silver CA - G2+========================+-----BEGIN CERTIFICATE-----+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT+BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X+DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3+aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG+9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644+N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH+6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu+MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h+qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5+FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs+ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc+celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X+CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/+BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB+tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P+4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F+kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L+3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx+/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa+DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP+e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu+WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ+DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub+DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u+-----END CERTIFICATE-----++GeoTrust Primary Certification Authority+========================================+-----BEGIN CERTIFICATE-----+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx+CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ+cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB+CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN+b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9+nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge+RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt+tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI+hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K+Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN+NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa+Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG+1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=+-----END CERTIFICATE-----++thawte Primary Root CA+======================+-----BEGIN CERTIFICATE-----+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv+cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3+MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg+SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv+KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT+FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs+oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ+1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc+q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K+aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p+afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF+AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE+uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89+jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH+z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==+-----END CERTIFICATE-----++VeriSign Class 3 Public Primary Certification Authority - G5+============================================================+-----BEGIN CERTIFICATE-----+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk+IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp+ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln+biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh+dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw+ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz+j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD+Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/+Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r+fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv+Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG+SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl++X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE+KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC+Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE+ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq+-----END CERTIFICATE-----++SecureTrust CA+==============+-----BEGIN CERTIFICATE-----+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy+dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe+BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX+OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t+DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH+GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b+01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH+ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/+BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj+aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ+KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu+SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf+mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ+nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=+-----END CERTIFICATE-----++Secure Global CA+================+-----BEGIN CERTIFICATE-----+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH+bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg+MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg+Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx+YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ+bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g+8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV+HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi+0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn+oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA+MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6++OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn+CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5+3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW+-----END CERTIFICATE-----++COMODO Certification Authority+==============================+-----BEGIN CERTIFICATE-----+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE+BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG+A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1+dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb+MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD+T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww+xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV+4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA+1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI+rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k+b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC+AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP+OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc+IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==+-----END CERTIFICATE-----++Network Solutions Certificate Authority+=======================================+-----BEGIN CERTIFICATE-----+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG+EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr+IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx+MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx+jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT+aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT+crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc+/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB+AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP+BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv+bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA+A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q+4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/+GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD+ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey+-----END CERTIFICATE-----++COMODO ECC Certification Authority+==================================+-----BEGIN CERTIFICATE-----+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC+R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE+ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB+dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix+GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo+b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X+4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni+wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG+FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA+U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=+-----END CERTIFICATE-----++Security Communication EV RootCA1+=================================+-----BEGIN CERTIFICATE-----+MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh+dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE+BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl+Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC+AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO+/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX+WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z+ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4+bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK+9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG+SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm+iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG+Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW+mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW+T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490+-----END CERTIFICATE-----++OISTE WISeKey Global Root GA CA+===============================+-----BEGIN CERTIFICATE-----+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE+BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG+A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH+bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD+VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw+IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5+IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9+Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg+Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD+d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ+/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R+LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw+AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ+KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm+MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY+okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=+-----END CERTIFICATE-----++Certigna+========+-----BEGIN CERTIFICATE-----+MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw+EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3+MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI+Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q+XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH+GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p+ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg+DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf+Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ+tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ+BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J+SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA+hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs++ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu+PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY+1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw+WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==+-----END CERTIFICATE-----++Deutsche Telekom Root CA 2+==========================+-----BEGIN CERTIFICATE-----+MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT+RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG+A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5+MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G+A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS+b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5+bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI+KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY+AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK+Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV+jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV+HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr+E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy+zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8+rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G+dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU+Cm26OWMohpLzGITY+9HPBVZkVw==+-----END CERTIFICATE-----++Cybertrust Global Root+======================+-----BEGIN CERTIFICATE-----+MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li+ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4+MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD+ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW+0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL+AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin+89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT+8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2+MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G+A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO+lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi+5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2+hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T+X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW+WL1WMRJOEcgh4LMRkWXbtKaIOM5V+-----END CERTIFICATE-----++ePKI Root Certification Authority+=================================+-----BEGIN CERTIFICATE-----+MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG+EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx+MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq+MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B+AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs+IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi+lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv+qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX+12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O+WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1++ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao+lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/+vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi+Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi+MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH+ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0+1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq+KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV+xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP+NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r+GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE+xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx+gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy+sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD+BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=+-----END CERTIFICATE-----++T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3+=============================================================================================================================+-----BEGIN CERTIFICATE-----+MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH+DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q+aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry+b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV+BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg+S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4+MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl+IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF+n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl+IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft+dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl+cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B+AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO+Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1+xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR+6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL+hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd+BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF+MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4+N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT+y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh+LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M+dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=+-----END CERTIFICATE-----++certSIGN ROOT CA+================+-----BEGIN CERTIFICATE-----+MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD+VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa+Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE+CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I+JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH+rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2+ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD+0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943+AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B+Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB+AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8+SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0+x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt+vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz+TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD+-----END CERTIFICATE-----++CNNIC ROOT+==========+-----BEGIN CERTIFICATE-----+MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE+ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw+OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD+o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz+VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT+VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or+czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK+y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC+wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S+lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5+Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM+O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8+BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2+G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m+mxE=+-----END CERTIFICATE-----++GeoTrust Primary Certification Authority - G3+=============================================+-----BEGIN CERTIFICATE-----+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz+NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo+YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT+LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI+hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j+K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE+c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C+IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu+dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr+2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9+cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE+Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s+t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt+-----END CERTIFICATE-----++thawte Primary Root CA - G2+===========================+-----BEGIN CERTIFICATE-----+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC+VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu+IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg+Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV+MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG+b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt+IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS+LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5+8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU+mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN+G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K+rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==+-----END CERTIFICATE-----++thawte Primary Root CA - G3+===========================+-----BEGIN CERTIFICATE-----+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv+cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w+ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh+d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD+VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG+A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A+MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At+P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY+7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW+vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ+KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK+A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC+8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm+er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=+-----END CERTIFICATE-----++GeoTrust Primary Certification Authority - G2+=============================================+-----BEGIN CERTIFICATE-----+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC+VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1+OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg+MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl+b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG+BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc+KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q++EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m+ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2+npaqBA+K+-----END CERTIFICATE-----++VeriSign Universal Root Certification Authority+===============================================+-----BEGIN CERTIFICATE-----+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk+IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u+IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv+cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl+IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj+1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP+MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72+9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I+AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR+tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G+CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O+a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3+Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx+Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx+P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P+wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4+mJO37M2CYfE45k+XmCpajQ==+-----END CERTIFICATE-----++VeriSign Class 3 Public Primary Certification Authority - G4+============================================================+-----BEGIN CERTIFICATE-----+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC+VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3+b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz+ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj+YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU+cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo+b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8+Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz+rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB+/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw+HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u+Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD+A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx+AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==+-----END CERTIFICATE-----++NetLock Arany (Class Gold) Főtanúsítvány+========================================+-----BEGIN CERTIFICATE-----+MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G+A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610+dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB+cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx+MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO+ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv+biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6+c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu+0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw+/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk+H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw+fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1+neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB+BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW+qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta+YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC+bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna+NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu+dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=+-----END CERTIFICATE-----++Staat der Nederlanden Root CA - G2+==================================+-----BEGIN CERTIFICATE-----+MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g+Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC+TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l+ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ+5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn+vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj+CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil+e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR+OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI+CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65+48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi+trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737+qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB+AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC+ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA+A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj+f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN+kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk+CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF+URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb+CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h+oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV+IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm+66+KAQ==+-----END CERTIFICATE-----++Hongkong Post Root CA 1+=======================+-----BEGIN CERTIFICATE-----+MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT+DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx+NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n+IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF+AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1+ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr+auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh+qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY+V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV+HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i+h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio+l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei+IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps+T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT+c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==+-----END CERTIFICATE-----++SecureSign RootCA11+===================+-----BEGIN CERTIFICATE-----+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi+SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS+b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw+KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1+cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL+TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO+wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq+g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP+O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA+bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX+t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh+OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r+bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ+Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01+y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061+lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=+-----END CERTIFICATE-----++ACEDICOM Root+=============+-----BEGIN CERTIFICATE-----+MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD+T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4+MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG+A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF+AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk+WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD+YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew+MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb+m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk+HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT+xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2+3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9+2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq+TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz+4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU+9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv+bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg+aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP+eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk+zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1+ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI+KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq+nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE+I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp+MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o+tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA==+-----END CERTIFICATE-----++Microsec e-Szigno Root CA 2009+==============================+-----BEGIN CERTIFICATE-----+MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER+MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv+c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o+dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE+BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt+U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA+fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG+0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA+pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm+1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC+AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf+QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE+FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o+lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX+I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775+tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02+yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi+LXpUq3DDfSJlgnCW+-----END CERTIFICATE-----++GlobalSign Root CA - R3+=======================+-----BEGIN CERTIFICATE-----+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv+YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh+bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT+aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt+iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ+0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3+rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl+OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2+xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE+FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7+lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8+EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E+bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18+YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r+kpeDMdmztcpHWD9f+-----END CERTIFICATE-----++Autoridad de Certificacion Firmaprofesional CIF A62634068+=========================================================+-----BEGIN CERTIFICATE-----+MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA+BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2+MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw+QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB+NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD+Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P+B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY+7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH+ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI+plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX+MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX+LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK+bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU+vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud+EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH+DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp+cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA+bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx+ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx+51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk+R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP+T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f+Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl+osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR+crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR+saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD+KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi+6Et8Vcad+qMUu2WFbm5PEn4KPJ2V+-----END CERTIFICATE-----++Izenpe.com+==========+-----BEGIN CERTIFICATE-----+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG+EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz+MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu+QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ+03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK+ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC+PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT+OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK+F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK+0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij++0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB+leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID+AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw++SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG+NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O+BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l+Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga+kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q+hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs+g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5+aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5+nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC+ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo+Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z+WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==+-----END CERTIFICATE-----++Chambers of Commerce Root - 2008+================================+-----BEGIN CERTIFICATE-----+MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu+QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy+Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl+ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF+EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl+cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC+AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA+XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj+h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/+ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk+NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g+D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331+lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ+0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj+ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2+EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI+G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ+BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh+bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh+bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC+CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH+AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1+wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH+3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU+RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6+M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1+YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF+9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK+zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG+nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg+OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ+-----END CERTIFICATE-----++Global Chambersign Root - 2008+==============================+-----BEGIN CERTIFICATE-----+MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu+QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx+NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg+Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ+QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD+aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf+VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf+XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0+ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB+/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA+TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M+H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe+Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF+HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh+wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB+AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT+BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE+BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm+aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm+aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp+1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0+dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG+/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6+ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s+dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg+9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH+foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du+qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr+P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq+c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z+09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B+-----END CERTIFICATE-----++Go Daddy Root Certificate Authority - G2+========================================+-----BEGIN CERTIFICATE-----+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu+MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G+A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI+hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq+9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd+fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl+NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9+BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac+vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r+5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV+N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1+-----END CERTIFICATE-----++Starfield Root Certificate Authority - G2+=========================================+-----BEGIN CERTIFICATE-----+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s+b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0+eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw+DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg+VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB+dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv+W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs+bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk+N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf+ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU+JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC+AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol+TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx+4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw+F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ+c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0+-----END CERTIFICATE-----++Starfield Services Root Certificate Authority - G2+==================================================+-----BEGIN CERTIFICATE-----+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s+b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl+IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV+BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT+dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC+AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2+h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa+hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP+LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB+rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG+SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP+E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy+xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza+YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6+-----END CERTIFICATE-----++AffirmTrust Commercial+======================+-----BEGIN CERTIFICATE-----+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw+MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF+AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb+DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV+C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6+BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww+MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV+HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC+AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG+hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi+qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv+0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh+sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=+-----END CERTIFICATE-----++AffirmTrust Networking+======================+-----BEGIN CERTIFICATE-----+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw+MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF+AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE+Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI+dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24+/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb+h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV+HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC+AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu+UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6+12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23+WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9+/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=+-----END CERTIFICATE-----++AffirmTrust Premium+===================+-----BEGIN CERTIFICATE-----+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS+BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy+OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy+dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A+MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn+BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV+5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd+GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R+p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI+S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04+6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5+/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv+MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC+6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S+L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV+BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg+IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60+g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb+zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==+-----END CERTIFICATE-----++AffirmTrust Premium ECC+=======================+-----BEGIN CERTIFICATE-----+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV+BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx+MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U+cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA+IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ+N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW+BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK+BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X+57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM+eQ==+-----END CERTIFICATE-----++Certum Trusted Network CA+=========================+-----BEGIN CERTIFICATE-----+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK+ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv+biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy+MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU+ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5+MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC+AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC+l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J+J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4+fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0+cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB+Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw+DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj+jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1+mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj+Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=+-----END CERTIFICATE-----++Certinomis - Autorité Racine+============================+-----BEGIN CERTIFICATE-----+MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK+Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg+LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG+A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw+JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD+ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa+wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly+Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw+2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N+jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q+c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC+lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb+xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g+530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna+4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G+A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ+KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x+WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva+R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40+nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B+CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv+JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE+qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b+WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE+wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/+vgt2Fl43N+bYdJeimUV5+-----END CERTIFICATE-----++TWCA Root Certification Authority+=================================+-----BEGIN CERTIFICATE-----+MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ+VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh+dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG+EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB+IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK+AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx+QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC+oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP+4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r+y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB+BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG+9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC+mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW+QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY+T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny+Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==+-----END CERTIFICATE-----++Security Communication RootCA2+==============================+-----BEGIN CERTIFICATE-----+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh+dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC+SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy+aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB+ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R+3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV+spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K+EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8+QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB+CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj+u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk+3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q+tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29+mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03+-----END CERTIFICATE-----++EC-ACC+======+-----BEGIN CERTIFICATE-----+MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE+BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w+ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD+VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE+CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT+BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7+MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt+SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl+Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh+cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK+w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT+ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4+HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a+E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw+0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD+VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0+Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l+dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ+lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa+Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe+l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2+E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D+5EI=+-----END CERTIFICATE-----++Hellenic Academic and Research Institutions RootCA 2011+=======================================================+-----BEGIN CERTIFICATE-----+MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT+O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y+aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z+IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT+AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z+IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo+IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB+AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI+1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa+71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u+8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH+3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8+MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu+b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt+XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8+TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD+/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N+7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4+-----END CERTIFICATE-----++Actalis Authentication Root CA+==============================+-----BEGIN CERTIFICATE-----+MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM+BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE+AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky+MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz+IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290+IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ+wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa+by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6+zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f+YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2+oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l+EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7+hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8+EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5+jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY+iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt+ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI+WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0+JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx+K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU++Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC+4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo+2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz+lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem+OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9+vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==+-----END CERTIFICATE-----++Trustis FPS Root CA+===================+-----BEGIN CERTIFICATE-----+MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG+EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290+IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV+BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ+RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk+H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa+cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt+o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA+AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd+BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c+GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC+yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P+8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV+l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl+iB6XzCGcKQENZetX2fNXlrtIzYE=+-----END CERTIFICATE-----++StartCom Certification Authority+================================+-----BEGIN CERTIFICATE-----+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0+NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT+37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ+Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0+dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu+c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv+bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0+aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0+aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t+L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG+cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5+fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm+N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN+Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T+tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX+e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA+2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs+HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib+D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8=+-----END CERTIFICATE-----++StartCom Certification Authority G2+===================================+-----BEGIN CERTIFICATE-----+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN+U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg+RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE+ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp+dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O+o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG+4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi+Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul+Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs+O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H+vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L+nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS+FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa+z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ+KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk+J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl++JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG+/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc+nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld+blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc+l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm+7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm+obp573PYtlNXLfbQ4ddI+-----END CERTIFICATE-----++Buypass Class 2 Root CA+=======================+-----BEGIN CERTIFICATE-----+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X+DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1+g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn+9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b+/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU+CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff+awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI+zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn+Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX+Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs+M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD+VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF+AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s+A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI+osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S+aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd+DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD+LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0+oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC+wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS+CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN+rJgWVqA=+-----END CERTIFICATE-----++Buypass Class 3 Root CA+=======================+-----BEGIN CERTIFICATE-----+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X+DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH+sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR+5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh+7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ+ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH+2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV+/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ+RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA+Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq+j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD+VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF+AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV+cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G+uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG+Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8+ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2+KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz+6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug+UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe+eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi+Cp/HuZc=+-----END CERTIFICATE-----++T-TeleSec GlobalRoot Class 3+============================+-----BEGIN CERTIFICATE-----+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx+MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3+DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK+9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU+NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF+iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W+0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr+AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb+fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT+ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h+P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==+-----END CERTIFICATE-----++EE Certification Centre Root CA+===============================+-----BEGIN CERTIFICATE-----+MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG+EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy+dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw+MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB+UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy+ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB+DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM+TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2+rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw+93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN+P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ+MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF+BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj+xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM+lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u+uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU+3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM+dcGWxZ0=+-----END CERTIFICATE-----++TURKTRUST Certificate Services Provider Root 2007+=================================================+-----BEGIN CERTIFICATE-----+MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP+MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg+QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X+DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl+a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN+BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp+bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N+YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv+KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya+KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT+rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC+AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s+Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I+aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO+Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb+BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK+poRq0Tl9+-----END CERTIFICATE-----++D-TRUST Root Class 3 CA 2 2009+==============================+-----BEGIN CERTIFICATE-----+MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK+DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe+Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE+LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD+ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA+BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv+KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z+p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC+AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ+4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y+eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw+MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G+PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw+OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm+2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0+o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV+dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph+X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=+-----END CERTIFICATE-----++D-TRUST Root Class 3 CA 2 EV 2009+=================================+-----BEGIN CERTIFICATE-----+MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw+OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw+OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS+egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh+zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T+7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60+sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35+11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv+cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v+ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El+MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp+b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh+c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P++PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05+nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX+ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA+NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv+w9y4AyHqnxbxLFS1+-----END CERTIFICATE-----++PSCProcert+==========+-----BEGIN CERTIFICATE-----+MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk+ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ+MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz+dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl+cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw+IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw+MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w+DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD+ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp+Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC+wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA+3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh+RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO+EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2+0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH+0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU+td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw+Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp+r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/+AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz+Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId+xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp+ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH+EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h+Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k+ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG+9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG+MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG+LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52+ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy+YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v+Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o+dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq+T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN+g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q+uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1+n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn+FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo+5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq+3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5+poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y+eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km+-----END CERTIFICATE-----++China Internet Network Information Center EV Certificates Root+==============================================================+-----BEGIN CERTIFICATE-----+MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV+BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D+aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg+Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG+A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM+PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl+cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y+jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV+98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H+klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23+KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC+7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD+glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5+0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM+7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws+ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0+5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8=+-----END CERTIFICATE-----++Swisscom Root CA 2+==================+-----BEGIN CERTIFICATE-----+MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG+EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy+dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2+MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln+aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM+LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo+ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ+wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH+Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a+SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS+NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab+mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY+Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3+qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw+HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O+BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu+MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO+v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ+82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz+o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs+a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx+OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW+mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o++sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC+rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX+5OfNeOI5wSsSnqaeG8XmDtkx2Q==+-----END CERTIFICATE-----++Swisscom Root EV CA 2+=====================+-----BEGIN CERTIFICATE-----+MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE+BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl+cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN+MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT+HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg+Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz+o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy+Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti+GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li+qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH+Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG+alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa+m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox+bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi+xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/+BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED+MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB+bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL+j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU+wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7+XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH+59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/+23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq+J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA+HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi+uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW+l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc=+-----END CERTIFICATE-----++CA Disig Root R1+================+-----BEGIN CERTIFICATE-----+MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp+ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp+c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy+3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8+u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2+m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk+CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa+YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6+vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL+LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX+ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is+XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ+04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR+xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B+LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM+CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb+VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85+YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS+ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix+lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N+UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ+a7+h89n07eLw4+1knj0vllJPgFOL+-----END CERTIFICATE-----++CA Disig Root R2+================+-----BEGIN CERTIFICATE-----+MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp+ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp+c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC+w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia+xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7+A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S+GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV+g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa+5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE+koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A+Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i+Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u+Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM+tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV+sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je+dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8+1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx+mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01+utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0+sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg+UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV+7+ZtsH8tZ/3zbBt1RqPlShfppNcL+-----END CERTIFICATE-----++ACCVRAIZ1+=========+-----BEGIN CERTIFICATE-----+MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB+SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1+MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH+UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC+DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM+jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0+RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD+aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ+0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG+WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7+8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR+5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J+9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK+Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw+Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu+Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2+VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM+Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA+QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh+AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA+YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj+AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA+IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk+aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0+dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2+MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI+hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E+R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN+YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49+nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ+TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3+sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h+I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg+Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd+3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p+EfbRD0tVNEYqi4Y7+-----END CERTIFICATE-----++TWCA Global Root CA+===================+-----BEGIN CERTIFICATE-----+MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT+CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD+QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK+EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg+Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C+nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV+r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR+Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV+tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W+KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99+sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p+yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn+kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI+zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC+AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g+cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn+LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M+8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg+/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg+lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP+A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m+i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8+EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3+zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=+-----END CERTIFICATE-----++TeliaSonera Root CA v1+======================+-----BEGIN CERTIFICATE-----+MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE+CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4+MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW+VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK++6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA+3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k+B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn+Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH+oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3+F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ+oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7+gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc+TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB+AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW+DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm+zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx+0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW+pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV+G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc+c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT+JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2+qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6+Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems+WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=+-----END CERTIFICATE-----++E-Tugra Certification Authority+===============================+-----BEGIN CERTIFICATE-----+MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w+DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls+ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN+ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw+NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx+QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl+cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD+DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A+MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd+hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K+CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g+ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ+BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0+E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz+rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq+jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn+rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5+dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB+/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG+MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK+kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO+XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807+VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo+a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc+dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV+KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT+Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0+8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G+C7TbO6Orb1wdtn7os4I07QZcJA==+-----END CERTIFICATE-----++T-TeleSec GlobalRoot Class 2+============================+-----BEGIN CERTIFICATE-----+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx+MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3+DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ+SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F+vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970+2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV+WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy+YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4+r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf+vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR+3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN+9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==+-----END CERTIFICATE-----++Atos TrustedRoot 2011+=====================+-----BEGIN CERTIFICATE-----+MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU+cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4+MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG+A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV+hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr+54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH++DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320+HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR+z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R+l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ+bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB+CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h+k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh+TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9+61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G+3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed+-----END CERTIFICATE-----++QuoVadis Root CA 1 G3+=====================+-----BEGIN CERTIFICATE-----+MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv+b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE+PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm+PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6+Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN+ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l+g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV+7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX+9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f+iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg+t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI+hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC+MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3+GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct+Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh+3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa+wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6+O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0+FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV+hMJKzRwuJIczYOXD+-----END CERTIFICATE-----++QuoVadis Root CA 2 G3+=====================+-----BEGIN CERTIFICATE-----+MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv+b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh+ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY+NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t+oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o+MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l+V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo+L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ+sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD+6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh+lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI+hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66+AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K+pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9+x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz+dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X+U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw+mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD+zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN+JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr+O3jtZsSOeWmD3n+M+-----END CERTIFICATE-----++QuoVadis Root CA 3 G3+=====================+-----BEGIN CERTIFICATE-----+MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv+b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286+IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL+Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe+6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3+I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U+VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7+5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi+Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM+dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt+rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI+hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px+KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS+t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ+TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du+DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib+Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD+hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX+0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW+dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2+PpxxVJkES/1Y+Zj0+-----END CERTIFICATE-----++DigiCert Assured ID Root G2+===========================+-----BEGIN CERTIFICATE-----+MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw+MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH+35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq+bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw+VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP+YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn+lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO+w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv+0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz+d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW+hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M+jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo+IhNzbM8m9Yop5w==+-----END CERTIFICATE-----++DigiCert Assured ID Root G3+===========================+-----BEGIN CERTIFICATE-----+MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD+VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1+MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ+BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb+RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs+KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF+UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy+YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy+1vUhZscv6pZjamVFkpUBtA==+-----END CERTIFICATE-----++DigiCert Global Root G2+=======================+-----BEGIN CERTIFICATE-----+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx+MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ+kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO+3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV+BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM+UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu+5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr+F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U+WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH+QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/+iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl+MrY=+-----END CERTIFICATE-----++DigiCert Global Root G3+=======================+-----BEGIN CERTIFICATE-----+MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD+VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw+MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k+aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C+AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O+YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp+Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y+3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34+VOKa5Vt8sycX+-----END CERTIFICATE-----++DigiCert Trusted Root G4+========================+-----BEGIN CERTIFICATE-----+MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw+HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1+MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3+d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp+pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o+k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa+vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY+QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6+MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm+mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7+f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH+dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8+oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud+DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD+ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY+ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr+yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy+7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah+ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN+5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb+/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa+5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK+G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP+82Z++-----END CERTIFICATE-----++WoSign+======+-----BEGIN CERTIFICATE-----+MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g+QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ+BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh+dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO+CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX+2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5+KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR++ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez+EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk+lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2+8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY+yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C+AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R+8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1+LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq+T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj+y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC+2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes+5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/+EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh+mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx+kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi+kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w==+-----END CERTIFICATE-----++WoSign China+============+-----BEGIN CERTIFICATE-----+MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv+geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD+VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k+8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5+uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85+dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5+Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy+b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc+76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m++Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6+yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX+GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA+A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6+yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY+r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115+j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A+kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97+qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y+jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB+ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv+T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO+kI26oQ==+-----END CERTIFICATE-----++COMODO RSA Certification Authority+==================================+-----BEGIN CERTIFICATE-----+MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE+BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG+A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv+biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC+R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE+ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB+dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn+dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ+FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt++5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG+x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX+2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL+OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3+sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C+GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5+WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E+FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w+DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt+rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj++nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg+tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW+sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp+pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA+zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq+ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52+7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I+LaZRfyHBNVOFBkpdn627G190+-----END CERTIFICATE-----++USERTrust RSA Certification Authority+=====================================+-----BEGIN CERTIFICATE-----+MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE+BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK+ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh+dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE+BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK+ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh+dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz+0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j+Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn+RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O++T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq+/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE+Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM+lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8+yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6++eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd+BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF+MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW+FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ+7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ+Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM+8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi+FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi+yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c+J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw+sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx+Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9+-----END CERTIFICATE-----++USERTrust ECC Certification Authority+=====================================+-----BEGIN CERTIFICATE-----+MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC+VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv+biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC+VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv+biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2+0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez+nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV+HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB+HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu+9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=+-----END CERTIFICATE-----++GlobalSign ECC Root CA - R4+===========================+-----BEGIN CERTIFICATE-----+MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD+EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD+EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl+OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P+AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV+MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF+JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=+-----END CERTIFICATE-----++GlobalSign ECC Root CA - R5+===========================+-----BEGIN CERTIFICATE-----+MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD+EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD+EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6+SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS+h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd+BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx+uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7+yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3+-----END CERTIFICATE-----++Staat der Nederlanden Root CA - G3+==================================+-----BEGIN CERTIFICATE-----+MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g+Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC+TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l+ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y+olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t+x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy+EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K+Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur+mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5+1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp+07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo+FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE+41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB+AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu+yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD+U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq+KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1+v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA+8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b+8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r+mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq+1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI+JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV+tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk=+-----END CERTIFICATE-----++Staat der Nederlanden EV Root CA+================================+-----BEGIN CERTIFICATE-----+MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g+RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M+MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl+cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk+SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW+O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r+0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8+Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV+XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr+08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV+0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd+74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx+fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa+ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI+eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu+c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq+5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN+b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN+f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi+5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4+WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK+DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy+eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==+-----END CERTIFICATE-----++IdenTrust Commercial Root CA 1+==============================+-----BEGIN CERTIFICATE-----+MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG+EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS+b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES+MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB+IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld+hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/+mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi+1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C+XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl+3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy+NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV+WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg+xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix+uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC+AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI+hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH+6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg+ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt+ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV+YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX+feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro+kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe+2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz+Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R+cGzM7vRX+Bi6hG6H+-----END CERTIFICATE-----++IdenTrust Public Sector Root CA 1+=================================+-----BEGIN CERTIFICATE-----+MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG+EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv+ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV+UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS+b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy+P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6+Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI+rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf+qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS+mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn+ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh+LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v+iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL+4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B+Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw+DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj+t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A+mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt+GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt+m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx+NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4+Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI+ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC+ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ+3Wl9af0AVqW3rLatt8o+Ae+c+-----END CERTIFICATE-----++Entrust Root Certification Authority - G2+=========================================+-----BEGIN CERTIFICATE-----+MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV+BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy+bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug+b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw+HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT+DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx+OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s+eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP+/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz+HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU+s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y+TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx+AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6+0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z+iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ+Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi+nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P++vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO+e4pIb4tF9g==+-----END CERTIFICATE-----++Entrust Root Certification Authority - EC1+==========================================+-----BEGIN CERTIFICATE-----+MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx+FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn+YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl+ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5+IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw+FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs+LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg+dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt+IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy+AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef+9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE+FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h+vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8+kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G+-----END CERTIFICATE-----++CFCA EV ROOT+============+-----BEGIN CERTIFICATE-----+MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE+CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB+IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw+MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD+DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV+BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD+7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN+uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW+ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7+xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f+py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K+gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol+hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ+tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf+BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB+/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB+ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q+ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua+4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG+E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX+BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn+aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy+PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX+kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C+ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su+-----END CERTIFICATE-----++TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5+====================================================+-----BEGIN CERTIFICATE-----+MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVFIxDzAN+BgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp+bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1Qg+RWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAw+ODA3MDFaFw0yMzA0MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0w+SwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnE+n2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRp+ZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB+CgKCAQEApCUZ4WWe60ghUEoI5RHwWrom/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537+jVJp45wnEFPzpALFp/kRGml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1m+ep5Fimh34khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z5UNP+9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0hO8EuPbJbKoCPrZV+4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QIDAQABo0IwQDAdBgNVHQ4EFgQUVpkH+HtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI+hvcNAQELBQADggEBAJ5FdnsXSDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPo+BP5yCccLqh0lVX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq+URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nfpeYVhDfwwvJl+lpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CFYv4HAqGEVka+lgqaE9chTLd8+B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW+qtB4Uu2NQvAmxU=+-----END CERTIFICATE-----++Certinomis - Root CA+====================+-----BEGIN CERTIFICATE-----+MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK+Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg+LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx+EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD+ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos+P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo+d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap+z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00+8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x+RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE+6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t+FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV+PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH+i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj+YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I+6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF+AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV+WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw+Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX+lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ+y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9+Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng+DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi+I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM+cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr+hkIGuUE=+-----END CERTIFICATE-----++OISTE WISeKey Global Root GB CA+===============================+-----BEGIN CERTIFICATE-----+MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG+EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl+ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw+MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD+VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds+b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX+scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP+rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk+9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o+Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg+GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB+/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI+hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD+dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0+VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui+HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic+Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=+-----END CERTIFICATE-----++Certification Authority of WoSign G2+====================================+-----BEGIN CERTIFICATE-----+MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQG+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNVBAMTJENlcnRpZmljYXRpb24g+QXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgx+CzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlm+aWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB+CgKCAQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPXJYY1kBai+XW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgOgHzKtB0TiGsOqCR3A9Du+W/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg9+5k4ot+vElbGs/V6r+kHLXZ1L3PR8du9nfwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BK+v0mUYQs4kI9dJGwlezt52eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC+AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJKoZI+hvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8fHulwqZm46qwtyeY+P0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G3CE4Q3RM+zD4F3LBMvzIkRfEzFg3+TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yySrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu++sif/a+RZQp4OBXllxcU3fngLDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS++7Q9LGOHSJDy7XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg=+-----END CERTIFICATE-----++CA WoSign ECC Root+==================+-----BEGIN CERTIFICATE-----+MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQswCQYDVQQGEwJD+TjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMTEkNBIFdvU2lnbiBFQ0MgUm9v+dDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQK+ExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZI+zj0CAQYFK4EEACIDYgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiU+t5v8KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES1ns2o0Iw+QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqv3VWqP2h4syhf3R+MluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0+Daupn75OcsqF1NnstTJFGG+rrQIwfcf3aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYu+a/GRspBl9JrmkO5K+-----END CERTIFICATE-----++SZAFIR ROOT CA2+===============+-----BEGIN CERTIFICATE-----+MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG+A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV+BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ+BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD+VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q+qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK+DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE+2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ+ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi+ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P+AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC+AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5+O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67+oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul+4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==+-----END CERTIFICATE-----++Certum Trusted Network CA 2+===========================+-----BEGIN CERTIFICATE-----+MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE+BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1+bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y+ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ+TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl+cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB+IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9+7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o+CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b+Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p+uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130+GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ+9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB+Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye+hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM+BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD+AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI+hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW+Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA+L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo+clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM+pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb+w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo+J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm+ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX+is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7+zAYspsbiDrW5viSP+-----END CERTIFICATE-----++Hellenic Academic and Research Institutions RootCA 2015+=======================================================+-----BEGIN CERTIFICATE-----+MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT+BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0+aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl+YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx+MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg+QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV+BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw+MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv+bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh+iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts++6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd+FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr+i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F+GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2+fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu+iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc+Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI+hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF++D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM+d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y+d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn+82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb+davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F+Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt+J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa+JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q+p/UsQu0yrbYhnr68+-----END CERTIFICATE-----++Hellenic Academic and Research Institutions ECC RootCA 2015+===========================================================+-----BEGIN CERTIFICATE-----+MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0+aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u+cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj+aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw+MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj+IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD+VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290+Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP+dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK+Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O+BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA+GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn+dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR+-----END CERTIFICATE-----++Certplus Root CA G1+===================+-----BEGIN CERTIFICATE-----+MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUAMD4xCzAJBgNV+BAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTAe+Fw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhD+ZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQAD+ggIPADCCAgoCggIBANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHN+r49aiZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt6kuJPKNx+Qv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP0FG7Yn2ksYyy/yARujVj+BYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTv+LRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDEEW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2+z4QTd28n6v+WZxcIbekN1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc+4nBvCGrch2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCTmehd+4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV4EJQeIQEQWGw9CEj+jy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPOWftwenMGE9nTdDckQQoRb5fc5+R++ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G+A1UdDgQWBBSowcCbkahDFXxdBie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHY+lwuBsTANBgkqhkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh+66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7/SMNkPX0XtPG+YX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BSS7CTKtQ+FjPlnsZlFT5kOwQ/+2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F+6ALEUz65noe8zDUa3qHpimOHZR4RKttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilX+CNQ314cnrUlZp5GrRHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWe+tUNy6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEVV/xuZDDC+VRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5g4VCXA9DO2pJNdWY9BW/++mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl++O/QmueD6i9a5jc2NvLi6Td11n0bt3++qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=+-----END CERTIFICATE-----++Certplus Root CA G2+===================+-----BEGIN CERTIFICATE-----+MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT+AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x+NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0+cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA+BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN+Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD+AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud+IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV+HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl+vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw==+-----END CERTIFICATE-----++OpenTrust Root CA G1+====================+-----BEGIN CERTIFICATE-----+MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV+BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcx+MB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM+CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEB+AQUAA4ICDwAwggIKAoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7fa+Yp6bwiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX/uMftk87+ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR077F9jAHiOH3BX2pfJLKO+YheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGPuY4zbGneWK2gDqdkVBFpRGZPTBKnjix9+xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLxp2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO+9z0M+Yo0FMT7MzUj8czxKselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq+3ywgsNw2TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+WG+Oi+n6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPwvFEVVJSmdz7QdFG9+URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYYEQRVzXR7z2FwefR7LFxckvzluFqr+TJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB+/zAdBgNVHQ4EFgQUl0YhVyE12jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/Px+N3DlCPaTKbYwDQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E+PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kfgLMtMrpkZ2Cv+uVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbSFXJfLkur1J1juONI5f6ELlgK+n0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLh+X4SPgPL0DTatdrOjteFkdjpY3H1PXlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80+nR14SohWZ25g/4/Ii+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcm+GS3tTAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L9109S5zvE/+bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/KyPu1svf0OnWZzsD2097+o+4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJAwSQiumPv+i2tCqjI40cHLI5kqiPAlxA+OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx+-----END CERTIFICATE-----++OpenTrust Root CA G2+====================+-----BEGIN CERTIFICATE-----+MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUAMEAxCzAJBgNV+BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcy+MB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM+CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEB+AQUAA4ICDwAwggIKAoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG++Ntmh/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78eCbY2albz+4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/61UWY0jUJ9gNDlP7ZvyCV+eYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fEFY8ElggGQgT4hNYdvJGmQr5J1WqIP7wt+UdGejeBSzFfdNTVY27SPJIjki9/ca1TSgSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz+3GIZ38i1MH/1PCZ1Eb3XG7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj+3CzMpSZyYhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaHvGOz+9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4t/bQWVyJ98LVtZR0+0dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/gh7PU3+06yzbXfZqfUAkBXKJOAGT+y3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB+/zAdBgNVHQ4EFgQUajn6QiL35okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59+M4PLuG53hq8wDQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz+Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0nXGEL8pZ0keI+mUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qTRmTFAHneIWv2V6CG1wZy7HBG+S4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpTwm+bREx50B1ws9efAvSyB7DH5fitIw6mVskp+EndI2S9G/Tvw/HRwkqWOOAgfZDC2t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ+6e18CL13zSdkzJTaTkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97kr+gCf2o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU3jg9CcCo+SmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eAiN1nE28daCSLT7d0geX0+YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14fWKGVyasvc0rQLW6aWQ9VGHgtPFGml4vm+u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK+-----END CERTIFICATE-----++OpenTrust Root CA G3+====================+-----BEGIN CERTIFICATE-----+MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT+AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X+DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w+ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA+IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B+ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB+/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf+BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM+BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta+3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB+-----END CERTIFICATE-----++ISRG Root X1+============+-----BEGIN CERTIFICATE-----+MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE+BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD+EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG+EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT+DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r+Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1+3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K+b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN+Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ+4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf+1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu+hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH+usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r+OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G+A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY+9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL+ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV+0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt+hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw+TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx+e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA+JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD+YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n+JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ+m+kXQ99b21/+jh5Xos1AnX5iItreGCc=+-----END CERTIFICATE-----++AC RAIZ FNMT-RCM+================+-----BEGIN CERTIFICATE-----+MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT+AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw+MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD+TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC+ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf+qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr+btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL+j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou+08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw+WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT+tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ+47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC+ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa+i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE+FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o+dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD+nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s+D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ+j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT+Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7+Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d+8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm+5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG+rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=+-----END CERTIFICATE-----++Amazon Root CA 1+================+-----BEGIN CERTIFICATE-----+MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD+VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1+MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv+bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC+ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH+FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ+gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t+dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce+VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB+/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3+DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM+CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy+8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa+2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2+xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5+-----END CERTIFICATE-----++Amazon Root CA 2+================+-----BEGIN CERTIFICATE-----+MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD+VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1+MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv+bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC+ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4+kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp+N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9+AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd+fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx+kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS+btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0+Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN+c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf++3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw+DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA+A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE+YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW+xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ+gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW+aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV+Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3+KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi+JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=+-----END CERTIFICATE-----++Amazon Root CA 3+================+-----BEGIN CERTIFICATE-----+MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG+EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy+NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ+MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB+f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr+Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43+rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc+eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==+-----END CERTIFICATE-----++Amazon Root CA 4+================+-----BEGIN CERTIFICATE-----+MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG+EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy+NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ+MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN+/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri+83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV+HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA+MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1+AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==+-----END CERTIFICATE-----++LuxTrust Global Root 2+======================+-----BEGIN CERTIFICATE-----+MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQELBQAwRjELMAkG+A1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNVBAMMFkx1eFRydXN0IEdsb2Jh+bCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUwMzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEW+MBQGA1UECgwNTHV4VHJ1c3QgUy5BLjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCC+AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wm+Kb3FibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTemhfY7RBi2+xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1EMShduxq3sVs35a0VkBC+wGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsnXpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm+1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkm+FRseTJIpgp7VkoGSQXAZ96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niF+wpN6cj5mj5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4gDEa/+a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+8kPREd8vZS9kzl8U+ubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2jX5t/Lax5Gw5CMZdjpPuKadUiDTSQ+MC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmHhFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB+/zBCBgNVHSAEOzA5MDcGByuBKwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5+Lmx1eHRydXN0Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT++Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQELBQADggIBAGoZ+FO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9BzZAcg4atmpZ1gDlaCDdLnIN+H2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTOjFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW+7MM3LGVYvlcAGvI1+ut7MV3CwRI9loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIu+ZY+kt9J/Z93I055cqqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWA+VWe+2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/JEAdemrR+TxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKrezrnK+T+Tb/mjuuqlPpmt+/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQfLSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc+7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31I+iyBMz2TWuJdGsE7RKlY6oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr+-----END CERTIFICATE-----++TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1+=============================================+-----BEGIN CERTIFICATE-----+MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT+D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr+IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g+TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp+ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD+VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt+c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth+bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11+IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A+MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8+6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc+wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0+3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9+WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU+ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ+KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh+AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc+lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R+e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j+q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=+-----END CERTIFICATE-----
mysql-haskell.cabal view
@@ -1,87 +1,270 @@-name:                mysql-haskell-version:             0.8.4.3-synopsis:            pure haskell MySQL driver-description:         pure haskell MySQL driver-license:             BSD3-license-file:        LICENSE-author:              winterland1989-maintainer:          winterland1989@gmail.com-copyright:           (c) 2016 Winterland-category:            Database-build-type:          Simple-extra-source-files:  ChangeLog.md, README.md-cabal-version:       >=1.10-homepage:            https://github.com/winterland1989/mysql-haskell-bug-reports:         https://github.com/winterland1989/mysql-haskell/issues+cabal-version:      3.4+name:               mysql-haskell+version:            1.2.5+synopsis:           pure haskell MySQL driver+description:        pure haskell MySQL driver.+license:            BSD-3-Clause+license-file:       LICENSE+author:             winterland1989+maintainer:         hi@jappie.me+copyright:          (c) 2016 Winterland+category:           Database+build-type:         Simple+extra-doc-files:    ChangeLog.md+extra-source-files:+  mozillaCAStore.pem+  README.md+  test/cert/ca-key.pem+  test/cert/ca.pem+  test/cert/server-cert.pem+  test/cert/server-key.pem+  test/cert/server-req.pem+  test/json-data/buffer-builder.json+  test/json-data/dates-fract.json+  test/json-data/dates.json+  test/json-data/example.json+  test/json-data/geometry.json+  test/json-data/integers.json+  test/json-data/jp10.json+  test/json-data/jp100.json+  test/json-data/jp50.json+  test/json-data/numbers.json+  test/json-data/twitter1.json+  test/json-data/twitter10.json+  test/json-data/twitter100.json+  test/json-data/twitter20.json+  test/json-data/twitter50.json +homepage:           https://github.com/winterland1989/mysql-haskell+bug-reports:        https://github.com/winterland1989/mysql-haskell/issues+ source-repository head   type:     git-  location: git://github.com/winterland1989/mysql-haskell.git+  location: https://github.com/winterland1989/mysql-haskell +flag crypton-1-1+  description: Build with crypton >= 1.1.0 (uses ram instead of memory for ByteArrayAccess)+  default: True+  manual: False++common common-options+  ghc-options:+    -Wall -Wincomplete-uni-patterns+    -Wincomplete-record-updates -Widentities -Wredundant-constraints+    -Wcpp-undef -fwarn-tabs -Wpartial-fields+    -Wunused-packages+    -fenable-th-splice-warnings+    -fno-omit-yields+  build-depends:+      base >=4.9.1.0 && <4.22.0+  default-language: GHC2021+ library-    exposed-modules:    Database.MySQL.Base-                    ,   Database.MySQL.TLS-                    ,   Database.MySQL.Protocol.Auth-                    ,   Database.MySQL.Protocol.Command-                    ,   Database.MySQL.Protocol.ColumnDef-                    ,   Database.MySQL.Protocol.Packet-                    ,   Database.MySQL.Protocol.MySQLValue-                    ,   Database.MySQL.Protocol.Escape-                    ,   Database.MySQL.BinLog-                    ,   Database.MySQL.BinLogProtocol.BinLogEvent-                    ,   Database.MySQL.BinLogProtocol.BinLogValue-                    ,   Database.MySQL.BinLogProtocol.BinLogMeta-                    ,   Database.MySQL.Connection-    other-modules:      Database.MySQL.Query-    build-depends:      base          >= 4.7 && < 5-                    ,   monad-loops   == 0.4.*-                    ,   network       >= 2.3 && < 4.0-                    ,   io-streams    >= 1.2 && < 2.0-                    ,   tcp-streams   >= 1.0 && < 1.1-                    ,   wire-streams  >= 0.1-                    ,   binary        >= 0.8.3-                    ,   binary-ieee754-                    ,   binary-parsers >= 0.2.1-                    ,   bytestring    >= 0.10.2.0-                    ,   text          >= 1.1 && < 1.3-                    ,   cryptonite    == 0.*-                    ,   memory        >= 0.14.4 && < 0.16-                    ,   time          >= 1.5.0-                    ,   scientific    == 0.3.*-                    ,   bytestring-lexing == 0.5.*-                    ,   blaze-textual     == 0.2.*-                    ,   word24            >= 1.0 && <= 3.0-                    ,   tls           >= 1.3.5 && < 1.6-                    ,   vector        >= 0.8+  import: common-options+  exposed-modules:+    Data.Binary.Parser+    Data.Binary.Parser.Numeric+    Data.Binary.Parser.Word8+    Data.Connection+    Data.Int.Int24+    Data.TLSSetting+    Data.Word.Word24+    Database.MySQL.Base+    Database.MySQL.BinLog+    Database.MySQL.BinLogProtocol.BinLogEvent+    Database.MySQL.BinLogProtocol.BinLogMeta+    Database.MySQL.BinLogProtocol.BinLogValue+    Database.MySQL.Connection+    Database.MySQL.Protocol.Auth+    Database.MySQL.Protocol.ColumnDef+    Database.MySQL.Protocol.Command+    Database.MySQL.Protocol.Escape+    Database.MySQL.Protocol.MySQLValue+    Database.MySQL.Protocol.Packet+    Database.MySQL.TLS+    System.IO.Streams.TCP+    System.IO.Streams.TLS -    default-language:    Haskell2010-    default-extensions:     DeriveDataTypeable-                        ,   DeriveGeneric-                        ,   MultiWayIf-                        ,   OverloadedStrings-    ghc-options:       -Wall+  other-modules:      Paths_mysql_haskell+  autogen-modules:    Paths_mysql_haskell+  hs-source-dirs:     src+  other-modules:      Database.MySQL.Query+  build-depends:+    asn1-encoding >=0.9 && <0.10,+    asn1-types >=0.3 && <0.4,+    binary >=0.8.3 && <0.9,+    blaze-textual >=0.2 && <0.3,+    bytestring >=0.10.2.0 && <0.12 || ^>=0.12.0,+    bytestring-lexing >=0.5 && <0.6,+    crypton-x509 >=1.5 && <2.0,+    crypton-x509-store >=1.5 && <2.0,+    crypton-x509-system >=1.5 && <2.0,+    data-default-class >=0.1.2 && <0.2 || ^>=0.2.0,+    deepseq >=1.4.6 && <1.5 || ^>=1.5.0,+    io-streams >=1.2 && <2.0,+    monad-loops >=0.4 && <0.5,+    network >=2.3 && <4.0,+    crypton-pem >=0.2.4 && <0.4,+    scientific >=0.3 && <0.4,+    text >=1.1 && <2.1 || ^>=2.1,+    time >=1.5.0 && <1.12 || ^>=1.12.2 || ^>=1.14,+    tls >=1.7.0 && <1.8 || ^>=1.8.0 || ^>=1.9.0 || ^>=2.0.0 || ^>=2.1.0 || ^>=2.2.0 || ^>=2.3.0 || ^>=2.4.0,+    vector >=0.8 && <0.13 || ^>=0.13.0,+    word-compat >=0.0 && <0.1 +  if flag(crypton-1-1)+    build-depends:+      crypton ^>=1.1.0,+      ram >=0.20 && <0.23+  else+    build-depends:+      crypton >=0.31 && <0.40 || ^>=1.0.0,+      memory >=0.14.4 && <0.19++  default-extensions:+    DeriveDataTypeable+    DeriveGeneric+    MultiWayIf+    OverloadedStrings++ test-suite test-    type: exitcode-stdio-1.0-    main-is: Main.hs-    other-modules:      BinaryRow-                    ,   BinaryRowNew-                    ,   BinLog-                    ,   BinLogNew-                    ,   TextRow-                    ,   TextRowNew-                    ,   ExecuteMany-    hs-source-dirs: test-    build-depends:  mysql-haskell-                  , base-                  , bytestring-                  , tasty >= 0.11 && < 2.0-                  , tasty-hunit-                  , text-                  , io-streams-                  , time-                  , vector-    default-extensions:     MultiWayIf-                        ,   OverloadedStrings-    ghc-options:         -threaded-    default-language:    Haskell2010+  import: common-options+  type:               exitcode-stdio-1.0+  main-is:            Main.hs+  other-modules:+    Aeson+    AesonBP+    BoundsCheck+    JSON+    QC.ByteString+    QC.Combinator+    QC.Common+    Orphans+    Sha1Scramble+    Sha256Scramble+    TCPStreams+    Word24++  hs-source-dirs:     test+  build-depends:+    attoparsec < 1.0,+    base16-bytestring >=1.0 && <2.0,+    binary >=0.8,+    bytestring >=0.10,+    deepseq,+    directory < 2.0,+    filepath < 2.0,+    io-streams,+    mysql-haskell,+    network,+    QuickCheck >=2.7 && <3.0,+    quickcheck-instances < 1.0,+    scientific >=0.3.0,+    tasty >=0.11 && <2.0,+    tasty-expected-failure < 1.0,+    tasty-hunit < 1.0,+    tasty-quickcheck >=0.8 && < 1.0,+    text,+    time,+    unordered-containers < 1.0,+    vector++  default-extensions:+    MultiWayIf+    OverloadedStrings++  ghc-options:        -threaded ++test-suite integration+  type:               exitcode-stdio-1.0+  main-is:            Integration.hs+  other-modules:+    BinaryRow+    BinaryRowNew+    BinLog+    BinLogNew+    CachingSha2+    ExecuteMany+    MysqlTests+    RoundtripBit+    RoundtripYear+    SelectOne+    TextRow+    TLSConnection+    TextRowNew+    UnixSocket++  hs-source-dirs:     test+  build-depends:+    base,+    bytestring >=0.10,+    directory,+    io-streams,+    mysql-haskell,+    tasty >=0.11 && <2.0,+    tasty-hunit < 1.0,+    text,+    time,+    vector++  default-extensions:+    MultiWayIf+    OverloadedStrings++  ghc-options:        -threaded+  default-language:   Haskell2010++benchmark binary-parsers-bench+  import: common-options+  other-modules:+    Aeson+    AesonBP+    Common+    HttpReq+    Network.Wai.Handler.Warp.ReadInt+    Network.Wai.Handler.Warp.RequestHeader++  build-depends:+    attoparsec,+    binary,+    bytestring,+    case-insensitive < 2,+    criterion >=1.1 && <1.2 || ^>=1.6.3,+    deepseq,+    directory < 1.4,+    filepath < 1.6,+    http-types < 1.0,+    mysql-haskell,+    scanner < 0.4,+    scientific,+    text,+    unordered-containers,+    vector++  hs-source-dirs:   binary-parser-bench+  main-is:          Bench.hs+  type:             exitcode-stdio-1.0+  ghc-options:      -O2++benchmark bench24+  import: common-options+  type:             exitcode-stdio-1.0+  hs-source-dirs:   word24-bench+  main-is:          Benchmark.hs+  build-depends:+    criterion >=1.1,+    deepseq >=1.2 && <2,+    mysql-haskell++  ghc-options:      -O2++-- enable to debug the RULES    +-- executable exe+--   import: common-options+--   main-is: Main.hs+--   hs-source-dirs:+--       app+--   build-depends:+--       mysql-haskell+--   ghc-options: -Wno-unused-packages
+ src/Data/Binary/Parser.hs view
@@ -0,0 +1,385 @@+{-# LANGUAGE BangPatterns #-}+-- |+-- Module      :  Data.Binary.Parser+-- Copyright   :  Daan Leijen 1999-2001, Bryan O'Sullivan 2007-2015, Winterland 2016+-- License     :  BSD3+--+-- Maintainer  :  drkoster@qq.com+-- Stability   :  experimental+-- Portability :  portable+--+-- This library provide parsec\/attoparsec style parsing combinators for+-- <http://hackage.haskell.org/package/binary binary>+-- package. By default, this module export combinators in "Data.Binary.Get",+-- "Data.Binary.Parser.Word8" and "Data.Binary.Parser.Numeric".+--+-- The behaviour of parsers here is different to that of the+-- similarly-named parser in Parsec, as this one is all-or-nothing.+-- To illustrate the difference, the following parser will fail under+-- Parsec given an input of @\"for\"@:+--+-- >string "foo" <|> string "for"+--+-- The reason for its failure is that the first branch is a+-- partial match, and will consume the letters @\'f\'@ and @\'o\'@+-- before failing.  In binary-parsers, the above parser will /succeed/ on+-- that input, because the failed first branch will consume nothing.+--+-- There're some redundant combinators get removed, for example:+--+-- @+-- choice == asum+-- count == replicateM+-- atEnd == isEmpty+-- take == getByteString+-- many1 == some+-- @+--+-- For fast byte set operations, please use <http://hackage.haskell.org/package/charset charset>+-- package.+--+-- It's recommanded to use 'parseOnly', 'parseDetail'... functions to run your parsers since these+-- functions are faster than binary's counter part by avoiding a small constant overhead.+-- Check 'parse' for detail.+--+-- = A few words on performance and backtracking+--+-- There's a common belief that parsers which support backtracking are slow, but it's not neccessarily+-- true in binary, because binary doesn't do book keeping if you doesn't use '<|>', 'lookAhead' or their+-- friends. Combinators in this library like 'peek', 'string'... also try to avoid backtracking so+-- it's faster to use them rather than do backtracking yourself, for example, 'peek' is faster than+-- @'lookAhead' 'getWord8'@. In practice, protocols are often designed to avoid backtracking.+-- For example, if you have following parser:+--+-- >branch1 <|> branch2 <|> (skipN 1 >> branch3)+--+-- And if you can select the right branch just by looking ahead one byte, then you can rewrite it to:+--+-- @+-- w <- peek+-- if  | w == b1 -> branch1+--     | w == b2 -> branch2+--     | w == b3 -> skipN 1 >> branch3+-- @+--+-- Binary performs as fast as a non-backtracking parser as long as you construct your parser+-- without using backtracking. And sometime backtracking is indeed neccessary, for example 'scientifically'+-- is almost impossible to implement correctly if you don't do backtracking.+--+module Data.Binary.Parser+    (+    -- * Running parsers+      Parser+    , parseOnly+    , parseLazy+    , parseDetail+    , parseDetailLazy+    , parse+    -- * Decoder conversion+    , maybeDecoder+    , eitherDecoder+    -- * Combinators+    , (<?>)+    , endOfInput+    , option+    , eitherP+    , match+    , many'+    , some'+    , sepBy+    , sepBy'+    , sepBy1+    , sepBy1'+    , manyTill+    , manyTill'+    , skipMany+    , skipMany1+    -- * Re-exports+    , module Data.Binary.Get+    , module Data.Binary.Parser.Word8+    , module Data.Binary.Parser.Numeric+    ) where++import           Control.Applicative+import           Control.Monad+import           Data.Binary.Get+import qualified Data.Binary.Get.Internal   as I+import           Data.Binary.Parser.Numeric+import           Data.Binary.Parser.Word8+import qualified Data.ByteString            as B+import qualified Data.ByteString.Lazy       as L+import qualified Data.ByteString.Lazy.Internal as L (ByteString(..))++--------------------------------------------------------------------------------++-- | Alias to 'Get' for attoparsec compatibility.+type Parser a = Get a++-- | Run a parser on 'B.ByteString'.+--+-- This function does not force a parser to consume all of its input.+-- Instead, any residual input will be discarded.  To force a parser+-- to consume all of its input, use something like this:+--+-- @parseOnly (myParser <* endOfInput)@+--+parseOnly :: Get a -> B.ByteString -> Either String a+parseOnly g bs =+    case pushEndOfInput (parse g bs) of+        Fail _ _ err -> Left err+        Done _ _ a -> Right a+        _ -> error "parseOnly: impossible error!"+{-# INLINE parseOnly #-}+++-- | Similar to 'parseOnly', but run a parser on lazy 'L.ByteString'.+--+parseLazy :: Get a -> L.ByteString -> Either String a+parseLazy g (L.Chunk bs lbs) =+    case pushEndOfInput (pushChunks (parse g bs) lbs) of+        Fail _ _ err -> Left err+        Done _ _ a -> Right a+        _ -> error "parseOnly: impossible error!"+parseLazy g L.Empty =+    case pushEndOfInput (parse g B.empty) of+        Fail _ _ err -> Left err+        Done _ _ a -> Right a+        _ -> error "parseOnly: impossible error!"+{-# INLINE parseLazy #-}++-- | Run a parser on 'B.ByteString'.+--+-- This function return full parsing results: the rest of input, stop offest and fail+-- message or parsing result.+--+-- /Since: 0.2.1.0/+--+parseDetail :: Get a+            -> B.ByteString+            -> Either (B.ByteString, ByteOffset, String) (B.ByteString, ByteOffset, a)+parseDetail g bs =+    case pushEndOfInput (parse g bs) of+        Fail rest offset err -> Left (rest, offset, err)+        Done rest offset a   -> Right (rest, offset, a)+        _ -> error "parseOnly: impossible error!"+{-# INLINE parseDetail #-}++-- | Similar to 'parseDetail', but run a parser on lazy 'L.ByteString'.+--+-- /Since: 0.2.1.0/+--+parseDetailLazy :: Get a+                -> L.ByteString+                -> Either (B.ByteString, ByteOffset, String) (B.ByteString, ByteOffset, a)+parseDetailLazy g (L.Chunk bs lbs) =+    case pushEndOfInput (pushChunks (parse g bs) lbs) of+        Fail rest offset err -> Left (rest, offset, err)+        Done rest offset a   -> Right (rest, offset, a)+        _ -> error "parseOnly: impossible error!"+parseDetailLazy g L.Empty =+    case pushEndOfInput (parse g B.empty) of+        Fail rest offset err -> Left (rest, offset, err)+        Done rest offset a   -> Right (rest, offset, a)+        _ -> error "parseOnly: impossible error!"+{-# INLINE parseDetailLazy #-}++-- | Run a 'Get' monad. See 'Decoder' for what to do next, like providing+-- input, handling decoding errors and to get the output value.+--+-- This's faster than 'runGetIncremental' becuase it provides an initial chunk rather+-- than feeding 'B.empty' and waiting for chunks, this overhead is noticeable when you're+-- running small getters over short 'ByteString' s.+--+-- /Since: 0.2.1.0/+--+parse :: Get a -> B.ByteString -> Decoder a+parse g bs = calculateOffset (loop (I.runCont g bs I.Done)) (fromIntegral $ B.length bs)+  where+    calculateOffset r !acc = case r of+        I.Done inp a -> Done inp (acc - fromIntegral (B.length inp)) a+        I.Fail inp s -> Fail inp (acc - fromIntegral (B.length inp)) s+        I.Partial k -> Partial $ \ms -> case ms of+                Nothing -> calculateOffset (k Nothing) acc+                Just i -> calculateOffset (k ms) (acc + fromIntegral (B.length i))+        I.BytesRead unused k -> calculateOffset (k $! (acc - unused)) acc++    loop r = case r of+        I.Partial k -> I.Partial $ \ms -> case ms of Just _ -> loop (k ms)+                                                     Nothing -> completeLoop (k ms)+        I.BytesRead n k -> I.BytesRead n (loop . k)+        I.Done _ _ -> r+        I.Fail _ _ -> r++    completeLoop r = case r of+        I.Partial k -> completeLoop (k Nothing)+        I.BytesRead n k -> I.BytesRead n (completeLoop . k)+        I.Fail _ _ -> r+        I.Done _ _ -> r++--------------------------------------------------------------------------------++-- | Convert a 'Decoder' value to a 'Maybe' value. A 'Partial' result+-- is treated as failure.+--+-- /Since: 0.2.3.0/+--+maybeDecoder :: Decoder r -> Maybe r+maybeDecoder (Done _ _ r) = Just r+maybeDecoder _            = Nothing+{-# INLINE maybeDecoder #-}++-- | Convert a 'Decoder' value to an 'Either' value. A 'Partial'+-- result is treated as failure.+--+-- /Since: 0.2.3.0/+--+eitherDecoder :: Decoder r -> Either String r+eitherDecoder (Done _ _ r)   = Right r+eitherDecoder (Fail _ _ msg) = Left msg+eitherDecoder _              = Left "Decoder: incomplete input"+{-# INLINE eitherDecoder #-}++--------------------------------------------------------------------------------++-- | Name the parser, in case failure occurs.+(<?>) :: Get a -> String -> Get a+(<?>) = flip label+infix 0 <?>+{-# INLINE (<?>) #-}++-- | Match only if all input has been consumed.+endOfInput :: Get ()+endOfInput = do+    e <- isEmpty+    unless e (fail "endOfInput")+{-# INLINE endOfInput #-}++-- | @option x p@ tries to apply action @p@. If @p@ fails without+-- consuming input, it returns the value @x@, otherwise the value+-- returned by @p@.+--+-- > priority  = option 0 (digitToInt <$> digit)+option :: Alternative f => a -> f a -> f a+option x p = p <|> pure x+{-# SPECIALIZE option :: a -> Get a -> Get a #-}++-- | Combine two alternatives.+eitherP :: (Alternative f) => f a -> f b -> f (Either a b)+eitherP a b = (Left <$> a) <|> (Right <$> b)+{-# INLINE eitherP #-}++-- | Return both the result of a parse and the portion of the input+-- that was consumed while it was being parsed.+match :: Get a -> Get (B.ByteString, a)+match p = do+    pos1 <- bytesRead+    (x, pos2) <- lookAhead $ (,) <$> p <*> bytesRead+    (,) <$> (getByteString . fromIntegral) (pos2 - pos1) <*> pure x+{-# INLINE match #-}++-- | A version of 'liftM2' that is strict in the result of its first+-- action.+liftM2' :: (Monad m) => (a -> b -> c) -> m a -> m b -> m c+liftM2' f a b = do+  !x <- a+  y <- b+  return (f x y)+{-# INLINE liftM2' #-}++-- | @many' p@ applies the action @p@ /zero/ or more times. Returns a+-- list of the returned values of @p@. The value returned by @p@ is+-- forced to WHNF.+--+-- >  word  = many' letter+many' :: (MonadPlus m) => m a -> m [a]+many' p = many_p+  where many_p = some_p `mplus` return []+        some_p = liftM2' (:) p many_p+{-# INLINE many' #-}++-- | @some' p@ applies the action @p@ /one/ or more times. Returns a+-- list of the returned values of @p@. The value returned by @p@ is+-- forced to WHNF.+--+-- >  word  = some' letter+some' :: (MonadPlus m) => m a -> m [a]+some' p = liftM2' (:) p (many' p)+{-# INLINE some' #-}++-- | @sepBy p sep@ applies /zero/ or more occurrences of @p@, separated+-- by @sep@. Returns a list of the values returned by @p@.+--+-- > commaSep p  = p `sepBy` (char ',')+sepBy :: Alternative f => f a -> f s -> f [a]+sepBy p s = liftA2 (:) p ((s *> sepBy1 p s) <|> pure []) <|> pure []+{-# SPECIALIZE sepBy :: Get a -> Get s -> Get [a] #-}++-- | @sepBy' p sep@ applies /zero/ or more occurrences of @p@, separated+-- by @sep@. Returns a list of the values returned by @p@. The value+-- returned by @p@ is forced to WHNF.+--+-- > commaSep p  = p `sepBy'` (char ',')+sepBy' :: (MonadPlus m) => m a -> m s -> m [a]+sepBy' p s = go `mplus` return []+  where go = liftM2' (:) p ((s >> sepBy1' p s) `mplus` return [])+{-# SPECIALIZE sepBy' :: Get a -> Get s -> Get [a] #-}++-- | @sepBy1 p sep@ applies /one/ or more occurrences of @p@, separated+-- by @sep@. Returns a list of the values returned by @p@.+--+-- > commaSep p  = p `sepBy1` (char ',')+sepBy1 :: Alternative f => f a -> f s -> f [a]+sepBy1 p s = go+    where go = liftA2 (:) p ((s *> go) <|> pure [])+{-# SPECIALIZE sepBy1 :: Get a -> Get s -> Get [a] #-}++-- | @sepBy1' p sep@ applies /one/ or more occurrences of @p@, separated+-- by @sep@. Returns a list of the values returned by @p@. The value+-- returned by @p@ is forced to WHNF.+--+-- > commaSep p  = p `sepBy1'` (char ',')+sepBy1' :: (MonadPlus m) => m a -> m s -> m [a]+sepBy1' p s = go+    where go = liftM2' (:) p ((s >> go) `mplus` return [])+{-# SPECIALIZE sepBy1' :: Get a -> Get s -> Get [a] #-}++-- | @manyTill p end@ applies action @p@ /zero/ or more times until+-- action @end@ succeeds, and returns the list of values returned by+-- @p@.  This can be used to scan comments:+--+-- >  simpleComment   = string "<!--" *> manyTill anyChar (string "-->")+--+-- (Note the overlapping parsers @anyChar@ and @string \"-->\"@.+-- While this will work, it is not very efficient, as it will cause a+-- lot of backtracking.)+manyTill :: Alternative f => f a -> f b -> f [a]+manyTill p end = go+    where go = (end *> pure []) <|> liftA2 (:) p go+{-# SPECIALIZE manyTill :: Get a -> Get b -> Get [a] #-}++-- | @manyTill' p end@ applies action @p@ /zero/ or more times until+-- action @end@ succeeds, and returns the list of values returned by+-- @p@.  This can be used to scan comments:+--+-- >  simpleComment   = string "<!--" *> manyTill' anyChar (string "-->")+--+-- (Note the overlapping parsers @anyChar@ and @string \"-->\"@.+-- While this will work, it is not very efficient, as it will cause a+-- lot of backtracking.)+--+-- The value returned by @p@ is forced to WHNF.+manyTill' :: (MonadPlus m) => m a -> m b -> m [a]+manyTill' p end = go+    where go = (end >> return []) `mplus` liftM2' (:) p go+{-# SPECIALIZE manyTill' :: Get a -> Get b -> Get [a] #-}++-- | Skip zero or more instances of an action.+skipMany :: Alternative f => f a -> f ()+skipMany p = go+    where go = (p *> go) <|> pure ()+{-# SPECIALIZE skipMany :: Get a -> Get () #-}++-- | Skip one or more instances of an action.+skipMany1 :: Alternative f => f a -> f ()+skipMany1 p = p *> skipMany p+{-# SPECIALIZE skipMany1 :: Get a -> Get () #-}
+ src/Data/Binary/Parser/Numeric.hs view
@@ -0,0 +1,165 @@+{-# LANGUAGE CPP          #-}+-- |+-- Module      :  Data.Binary.Parser.Numeric+-- Copyright   :  Bryan O'Sullivan 2007-2015, Winterland 2016+-- License     :  BSD3+--+-- Maintainer  :  drkoster@qq.com+-- Stability   :  experimental+-- Portability :  unknown+--+-- Simple, efficient combinator parsing for numeric values.+--+module Data.Binary.Parser.Numeric where++import           Control.Applicative+import           Control.Monad+import           Data.Binary.Get.Internal+import qualified Data.Binary.Parser.Word8     as W+import qualified Data.ByteString              as B+import qualified Data.ByteString.Lex.Integral as LexInt+import           Data.Int+import           Data.Scientific              (Scientific (..))+import qualified Data.Scientific              as Sci+import           Data.Word++#define  MINUS    45+#define  PLUS     43+#define  LITTLE_E 101+#define  BIG_E    69+#define  DOT      46++-- | Parse and decode an unsigned hexadecimal number.  The hex digits+-- @\'a\'@ through @\'f\'@ may be upper or lower case.+--+-- This parser does not accept a leading @\"0x\"@ string.+--+hexadecimal :: (Integral a) => Get a+hexadecimal = do+    bs <- W.takeWhile1 W.isHexDigit+    case LexInt.readHexadecimal bs of+        Just (x, _) -> return x+        Nothing -> fail "hexadecimal: impossible"+{-# SPECIALISE hexadecimal :: Get Int #-}+{-# SPECIALISE hexadecimal :: Get Int8 #-}+{-# SPECIALISE hexadecimal :: Get Int16 #-}+{-# SPECIALISE hexadecimal :: Get Int32 #-}+{-# SPECIALISE hexadecimal :: Get Int64 #-}+{-# SPECIALISE hexadecimal :: Get Integer #-}+{-# SPECIALISE hexadecimal :: Get Word #-}+{-# SPECIALISE hexadecimal :: Get Word8 #-}+{-# SPECIALISE hexadecimal :: Get Word16 #-}+{-# SPECIALISE hexadecimal :: Get Word32 #-}+{-# SPECIALISE hexadecimal :: Get Word64 #-}++-- | Parse and decode an unsigned decimal number.+--+decimal :: Integral a => Get a+decimal = do+    bs <- W.takeWhile1 W.isDigit+    return $! LexInt.readDecimal_ bs+{-# SPECIALISE decimal :: Get Int #-}+{-# SPECIALISE decimal :: Get Int8 #-}+{-# SPECIALISE decimal :: Get Int16 #-}+{-# SPECIALISE decimal :: Get Int32 #-}+{-# SPECIALISE decimal :: Get Int64 #-}+{-# SPECIALISE decimal :: Get Integer #-}+{-# SPECIALISE decimal :: Get Word #-}+{-# SPECIALISE decimal :: Get Word8 #-}+{-# SPECIALISE decimal :: Get Word16 #-}+{-# SPECIALISE decimal :: Get Word32 #-}+{-# SPECIALISE decimal :: Get Word64 #-}++-- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign+-- character.+--+signed :: Num a => Get a -> Get a+signed p = do+    w <- W.peek+    if w == MINUS+        then W.skipN 1 >> negate <$> p+        else if w == PLUS then W.skipN 1 >> p else p+{-# SPECIALISE signed :: Get Int -> Get Int #-}+{-# SPECIALISE signed :: Get Int8 -> Get Int8 #-}+{-# SPECIALISE signed :: Get Int16 -> Get Int16 #-}+{-# SPECIALISE signed :: Get Int32 -> Get Int32 #-}+{-# SPECIALISE signed :: Get Int64 -> Get Int64 #-}+{-# SPECIALISE signed :: Get Integer -> Get Integer #-}++-- | Parse a rational number.+--+-- The syntax accepted by this parser is the same as for 'double'.+--+-- /Note/: this parser is not safe for use with inputs from untrusted+-- sources.  An input with a suitably large exponent such as+-- @"1e1000000000"@ will cause a huge 'Integer' to be allocated,+-- resulting in what is effectively a denial-of-service attack.+--+-- In most cases, it is better to use 'double' or 'scientific'+-- instead.+--+rational :: Fractional a => Get a+rational = scientifically realToFrac+{-# SPECIALIZE rational :: Get Double #-}+{-# SPECIALIZE rational :: Get Float #-}+{-# SPECIALIZE rational :: Get Rational #-}+{-# SPECIALIZE rational :: Get Scientific #-}++-- | Parse a rational number and round to 'Double'.+--+-- This parser accepts an optional leading sign character, followed by+-- at least one decimal digit.  The syntax similar to that accepted by+-- the 'read' function, with the exception that a trailing @\'.\'@ or+-- @\'e\'@ /not/ followed by a number is not consumed.+--+-- Examples with behaviour identical to 'read':+--+-- >parseOnly double "3"     == Right ("",1,3.0)+-- >parseOnly double "3.1"   == Right ("",3,3.1)+-- >parseOnly double "3e4"   == Right ("",3,30000.0)+-- >parseOnly double "3.1e4" == Right ("",5,31000.0)+--+-- >parseOnly double ".3"    == Left (".3",0,"takeWhile1")+-- >parseOnly double "e3"    == Left ("e3",0,"takeWhile1")+--+-- Examples of differences from 'read':+--+-- >parseOnly double "3.foo" == Right (".foo",1,3.0)+-- >parseOnly double "3e"    == Right ("e",1,3.0)+--+-- This function does not accept string representations of \"NaN\" or+-- \"Infinity\".+--+double :: Get Double+double = scientifically Sci.toRealFloat++-- | Parse a scientific number.+--+-- The syntax accepted by this parser is the same as for 'double'.+--+scientific :: Get Scientific+scientific = scientifically id++-- | Parse a scientific number and convert to result using a user supply function.+--+-- The syntax accepted by this parser is the same as for 'double'.+--+scientifically :: (Scientific -> a) -> Get a+scientifically h = do+    sign <- W.peek+    when (sign == PLUS || sign == MINUS) (W.skipN 1)+    intPart <- decimal+    sci <- (do fracDigits <- W.word8 DOT >> W.takeWhile1 W.isDigit+               let e' = B.length fracDigits+                   intPart' = intPart * (10 ^ e')+                   fracPart = LexInt.readDecimal_ fracDigits+               parseE (intPart' + fracPart) e'+           ) <|> (parseE intPart 0)++    if sign /= MINUS then return $! h sci else return $! h (negate sci)+  where+    parseE c e =+        (do _ <- W.satisfy (\w -> w ==  LITTLE_E || w == BIG_E)+            (Sci.scientific c . (subtract e) <$> signed decimal)) <|> return (Sci.scientific c (negate e))+    {-# INLINE parseE #-}+{-# INLINE scientifically #-}
+ src/Data/Binary/Parser/Word8.hs view
@@ -0,0 +1,314 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP          #-}+-- |+-- Module      :  Data.Binary.Parser.Word8+-- Copyright   :  Bryan O'Sullivan 2007-2015, Winterland 2016+-- License     :  BSD3+--+-- Maintainer  :  drkoster@qq.com+-- Stability   :  experimental+-- Portability :  unknown+--+-- Simple, efficient combinator parsing for 'B.ByteString' strings.+--+module Data.Binary.Parser.Word8 where++import           Control.Applicative+import           Control.Monad+import           Data.Binary.Get+import           Data.Binary.Get.Internal+import           Data.ByteString          (ByteString)+import qualified Data.ByteString          as B+import           Data.ByteString.Internal (ByteString (..))+import qualified Data.ByteString.Unsafe   as B+import           Data.Word+import           Foreign.ForeignPtr       (withForeignPtr)+import           Foreign.Ptr              (minusPtr, plusPtr)+import qualified Foreign.Storable         as Storable (Storable (peek))+import           Prelude                  hiding (takeWhile)++#if MIN_VERSION_bytestring(0,10,6)+import           Data.ByteString.Internal (accursedUnutterablePerformIO)+#else+import           Data.ByteString.Internal (inlinePerformIO)++{-# INLINE accursedUnutterablePerformIO #-}+-- | You must be truly desperate to come to me for help.+accursedUnutterablePerformIO :: IO a -> a+accursedUnutterablePerformIO = inlinePerformIO+#endif++--------------------------------------------------------------------------------++-- | Match any byte, to perform lookahead. Returns 'Nothing' if end of+-- input has been reached. Does not consume any input.+--+peekMaybe :: Get (Maybe Word8)+peekMaybe = do+    e <- isEmpty+    if e then return Nothing+         else Just <$> peek+{-# INLINE peekMaybe #-}++-- | Match any byte, to perform lookahead.  Does not consume any+-- input, but will fail if end of input has been reached.+--+peek :: Get Word8+peek = do+    ensureN 1+    bs <- get+    return (B.unsafeHead bs)+{-# INLINE peek #-}++-- | The parser @satisfy p@ succeeds for any byte for which the+-- predicate @p@ returns 'True'. Returns the byte that is actually+-- parsed.+--+-- >digit = satisfy isDigit+-- >    where isDigit w = w >= 48 && w <= 57+--+satisfy :: (Word8 -> Bool) -> Get Word8+satisfy p = do+    ensureN 1+    bs <- get+    let w = B.unsafeHead bs+    if p w then put (B.unsafeTail bs) >> return w+           else fail "satisfy"+{-# INLINE satisfy #-}++-- | The parser @satisfyWith f p@ transforms a byte, and succeeds if+-- the predicate @p@ returns 'True' on the transformed value. The+-- parser returns the transformed byte that was parsed.+--+satisfyWith :: (Word8 -> a) -> (a -> Bool) -> Get a+satisfyWith f p = do+    ensureN 1+    bs <- get+    let w = B.unsafeHead bs+        r = f w+    if p r then put (B.unsafeTail bs) >> return r+           else fail "satisfyWith"+{-# INLINE satisfyWith #-}++-- | Match a specific byte.+--+word8 :: Word8 -> Get ()+word8 c = do+    ensureN 1+    bs <- get+    let w = B.unsafeHead bs+    if c == w then put (B.unsafeTail bs)+              else fail "word8"+{-# INLINE word8 #-}++-- | Match any byte.+--+anyWord8 :: Get Word8+anyWord8 = getWord8+{-# INLINE anyWord8 #-}++-- | The parser @skipWord8 p@ succeeds for any byte for which the predicate @p@ returns 'True'.+--+skipWord8 :: (Word8 -> Bool) -> Get ()+skipWord8 p = do+    ensureN 1+    bs <- get+    let w = B.unsafeHead bs+    if p w then put (B.unsafeTail bs)+              else fail "skip"+{-# INLINE skipWord8 #-}++--------------------------------------------------------------------------------++-- | This is a faster version of 'skip' for small N (smaller than chunk size).+--+skipN :: Int -> Get ()+skipN n = do+    bs <- get+    let l = B.length bs+    if l > n then put (B.unsafeDrop n bs)+             else skip n+{-# INLINE skipN #-}++-- | Consume input as long as the predicate returns 'False' or reach the end of input,+-- and return the consumed input.+--+takeTill :: (Word8 -> Bool) -> Get ByteString+takeTill p = do+    bs <- get+    let (want, rest) = B.break p bs+    put rest+    if B.null rest then B.concat . reverse <$> go [want] else return want+  where+    go acc = do+        e <- isEmpty -- isEmpty will draw input here+        if e+        then return acc+        else do+            bs <- get+            let (want, rest) = B.break p bs+                acc' = want : acc+            put rest+            if B.null rest then go acc' else return acc'+{-# INLINE takeTill #-}++-- | Consume input as long as the predicate returns 'True' or reach the end of input,+-- and return the consumed input.+--+takeWhile :: (Word8 -> Bool) -> Get ByteString+takeWhile p = do+    bs <- get+    let (want, rest) = B.span p bs+    put rest+    if B.null rest then B.concat . reverse <$> go [want] else return want+  where+    go acc = do+        e <- isEmpty+        if e+        then return acc+        else do+            bs <- get+            let (want, rest) = B.span p bs+                acc' = want : acc+            put rest+            if B.null rest then go acc' else return acc'+{-# INLINE takeWhile #-}++-- | Similar to 'takeWhile', but requires the predicate to succeed on at least one byte+-- of input: it will fail if the predicate never returns 'True' or reach the end of input+--+takeWhile1 :: (Word8 -> Bool) -> Get ByteString+takeWhile1 p = do+    bs <- takeWhile p+    if B.null bs then fail "takeWhile1" else return bs+{-# INLINE takeWhile1 #-}++-- | Skip past input for as long as the predicate returns 'True'.+--+skipWhile :: (Word8 -> Bool) -> Get ()+skipWhile p = do+    bs <- get+    let rest = B.dropWhile p bs+    put rest+    when (B.null rest) go+  where+    go = do+        e <- isEmpty+        unless e $ do+            bs <- get+            let rest = B.dropWhile p bs+            put rest+            when (B.null rest) go+{-# INLINE skipWhile #-}++-- | Skip over white space using 'isSpace'.+--+skipSpaces :: Get ()+skipSpaces = skipWhile isSpace+{-# INLINE skipSpaces #-}++-- | @string s@ parses a sequence of bytes that identically match @s@.+--+string :: ByteString -> Get ()+string bs = do+    let l = B.length bs+    bs' <- get+    if l <= B.length bs'              -- current chunk is enough+    then if B.unsafeTake l bs' == bs+        then put (B.unsafeDrop l bs')+        else fail "string"+    else do+        ensureN l+        bs'' <- get+        if B.unsafeTake l bs'' == bs+        then put (B.unsafeDrop l bs'')+        else fail "string"+{-# INLINE string #-}++-- | A stateful scanner.  The predicate consumes and transforms a+-- state argument, and each transformed state is passed to successive+-- invocations of the predicate on each byte of the input until one+-- returns 'Nothing' or the input ends.+--+-- This parser does not fail.  It will return an empty string if the+-- predicate returns 'Nothing' on the first byte of input.+--+scan :: s -> (s -> Word8 -> Maybe s) -> Get ByteString+scan s0 consume = withInputChunks s0 consume' B.concat (return . B.concat)+  where+    consume' s1 (PS fp off len) = accursedUnutterablePerformIO $+        withForeignPtr fp $ \ptr0 -> do+            let start = ptr0 `plusPtr` off+                end   = start `plusPtr` len+            go fp off start end start s1+    go fp off start end ptr !s+        | ptr < end = do+            w <- Storable.peek ptr+            case consume s w of+                Just s' -> go fp off start end (ptr `plusPtr` 1) s'+                _       -> do+                    let !len1 = ptr `minusPtr` start+                        !off2 = off + len1+                        !len2 = end `minusPtr` ptr+                    return (Right (PS fp off len1, PS fp off2 len2))+        | otherwise = return (Left s)+{-# INLINE scan #-}++-- | Similar to 'scan', but working on 'ByteString' chunks, The predicate+-- consumes a 'ByteString' chunk and transforms a state argument,+-- and each transformed state is passed to successive invocations of+-- the predicate on each chunk of the input until one chunk got splited to+-- @Right (ByteString, ByteString)@ or the input ends.+--+scanChunks :: s -> Consume s -> Get ByteString+scanChunks s consume = withInputChunks s consume B.concat (return . B.concat)+{-# INLINE scanChunks #-}++--------------------------------------------------------------------------------++-- | Fast 'Word8' predicate for matching ASCII space characters+--+-- >isSpace w = w == 32 || w - 9 <= 4+--+isSpace :: Word8 -> Bool+isSpace w = w == 32 || w - 9 <= 4+{-# INLINE isSpace #-}++-- | Decimal digit predicate.+--+isDigit :: Word8 -> Bool+isDigit w = w - 48 <= 9+{-# INLINE isDigit #-}++-- | Hex digit predicate.+--+isHexDigit :: Word8 -> Bool+isHexDigit w = (w >= 48 && w <= 57) || (w >= 97 && w <= 102) || (w >= 65 && w <= 70)+{-# INLINE isHexDigit #-}++-- | A predicate that matches either a space @\' \'@ or horizontal tab+-- @\'\\t\'@ character.+--+isHorizontalSpace :: Word8 -> Bool+isHorizontalSpace w = w == 32 || w == 9+{-# INLINE isHorizontalSpace #-}++-- | A predicate that matches either a carriage return @\'\\r\'@ or+-- newline @\'\\n\'@ character.+--+isEndOfLine :: Word8 -> Bool+isEndOfLine w = w == 13 || w == 10+{-# INLINE isEndOfLine #-}++--------------------------------------------------------------------------------++-- | Match either a single newline byte @\'\\n\'@, or a carriage+-- return followed by a newline byte @\"\\r\\n\"@.+endOfLine :: Get ()+endOfLine = do+    w <- getWord8+    case w of+        10 -> return ()+        13 -> word8 10+        _  -> fail "endOfLine"+{-# INLINE endOfLine #-}
+ src/Data/Connection.hs view
@@ -0,0 +1,42 @@+module Data.Connection where++import qualified Data.ByteString           as B+import qualified Data.ByteString.Lazy.Internal as L+import qualified System.IO.Streams         as S++-- | A simple connection abstraction.+--+-- 'Connection' s from this package are supposed to have following properties:+--+--  * 'S.InputStream' is choosen to simplify streaming processing.+--  You can easily push back some data with 'S.unRead',+--  reading 'S.InputStream' will block until GHC IO manager find data is ready, for example:+--  @'S.readExactly' 1024@ will block until at least 1024 bytes are available.+--+--  * The type @'L.ByteString' -> 'IO' ()@ is choosen because it worked well with haskell's builder infrastructure.+--  <http://hackage.haskell.org/package/network-2.6.2.1/docs/Network-Socket-ByteString.html#g:2 vector-IO>+--  is used automatically when there's more than one chunk to send to save system call.+--+--  * 'connExtraInfo' field store extra data about the connection, 'N.SockAddr' for example.+--  You can also use this field as a type tag to distinguish different type of connection.+--+--  * 'close' should close connection resource, thus the 'Connection' shouldn't be used anymore+--  after 'close' is called.+--+--  * You should make sure there's no pending recv/send before you 'close' a 'Connection'.+--  That means either you call 'close' in the same thread you recv/send, or use async exception+--  to terminate recv/send thread before call 'close' in other thread(such as a reaper thread).+--  Otherwise you may run into+--  <https://mail.haskell.org/pipermail/haskell-cafe/2014-September/115823.html race-connections>.+--+--  * Exception or closed by other peer during recv/send will NOT close underline socket,+--  you should always use 'close' with 'E.bracket' to ensure safety.+--+--  @since 1.0+--+data Connection a = Connection+    { source        :: {-# UNPACK #-} !(S.InputStream B.ByteString)   -- ^ receive data as 'S.InputStream'+    , send          :: L.ByteString -> IO ()                          -- ^ send data with connection+    , close         :: IO ()                                          -- ^ close connection+    , connExtraInfo :: a                                              -- ^ extra info+    }
+ src/Data/Int/Int24.hs view
@@ -0,0 +1,250 @@+{-# OPTIONS_GHC -Wno-inline-rule-shadowing #-}++{-# LANGUAGE BangPatterns      #-}+{-# LANGUAGE CPP               #-}+{-# LANGUAGE MagicHash         #-}+{-# LANGUAGE NoImplicitPrelude #-}++#if !MIN_VERSION_base(4,8,0)+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE StandaloneDeriving #-}+#endif++-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Int.Int24+-- Copyright   :  (c) The University of Glasgow 1997-2002+-- License     :  see src/Data/LICENSE+--+-- Stability   :  experimental+-- Portability :  non-portable (GHC Extensions)+--+-- The 24 bit integral datatype, 'Int24'.+--+-----------------------------------------------------------------------------++module Data.Int.Int24 (+  -- * Int24 type+  Int24(..)+  -- * Internal helper+  , narrow24Int#+  ) where++import           Data.Bits+import           Data.Data+import           Data.Maybe+import           Data.Word.Word24+import           Foreign.Storable++import           GHC.Arr+import           GHC.Base+import           GHC.Enum+import           GHC.Int.Compat+import           GHC.Integer (smallInteger, integerToInt)+import           GHC.Num hiding (integerToInt)+import           GHC.Ptr+import           GHC.Read+import           GHC.Real+import           GHC.Show+import           GHC.Word.Compat++import           Control.DeepSeq++#if !MIN_VERSION_base(4,8,0)+import           Data.Typeable+#endif++------------------------------------------------------------------------++-- Int24 is represented in the same way as Int. Operations may assume+-- and must ensure that it holds only values from its logical range.++-- | 24-bit signed integer type+data Int24 = I24# Int# deriving (Eq, Ord)++#if !MIN_VERSION_base(4,8,0)+deriving instance Typeable Int24+#endif++instance NFData Int24  where rnf !_ = ()++int24Type :: DataType+int24Type = mkIntType "Data.Word.Int24.Int24"++instance Data Int24 where+  toConstr x = mkIntegralConstr int24Type x+  gunfold _ z c = case constrRep c of+                    (IntConstr x) -> z (fromIntegral x)+                    _ -> error $ "Data.Data.gunfold: Constructor " ++ show c+                                 ++ " is not of type Int24."+  dataTypeOf _ = int24Type++-- the narrowings are primops in GHC; I don't have that luxury.+-- if the 24th bit (from right) is on, the value is negative, so+-- fill the uppermost bits with 1s.  Otherwise clear them to 0s.+narrow24Int# :: Int# -> Int#+narrow24Int# x# = if isTrue# ((x'# `and#` mask#) `eqWord#` mask#)+    then word2Int# (x'# `or#`  int2Word# m1#)+    else word2Int# (x'# `and#` int2Word# m2#)+  where+    !x'#   = int2Word# x#+    !mask# = int2Word# 0x00800000#+    !(I# m1#) = -8388608+    !(I# m2#) = 16777215++instance Show Int24 where+    showsPrec p x = showsPrec p (fromIntegral x :: Int)++instance Num Int24 where+    (I24# x#) + (I24# y#)  = I24# (narrow24Int# (x# +# y#))+    (I24# x#) - (I24# y#)  = I24# (narrow24Int# (x# -# y#))+    (I24# x#) * (I24# y#)  = I24# (narrow24Int# (x# *# y#))+    negate (I24# x#)       = I24# (narrow24Int# (negateInt# x#))+    abs x | x >= 0         = x+          | otherwise      = negate x+    signum x | x > 0       = 1+    signum 0               = 0+    signum _               = -1+    fromInteger i          = I24# (narrow24Int# (integerToInt i))++instance Real Int24 where+    toRational x = toInteger x % 1++instance Enum Int24 where+    succ x+        | x /= maxBound = x + 1+        | otherwise     = succError "Int24"+    pred x+        | x /= minBound = x - 1+        | otherwise     = predError "Int24"+    toEnum i@(I# i#)+        | i >= fromIntegral (minBound::Int24) && i <= fromIntegral (maxBound::Int24)+                        = I24# i#+        | otherwise     = toEnumError "Int24" i (minBound::Int24, maxBound::Int24)+    fromEnum (I24# x#)  = I# x#+    enumFrom            = boundedEnumFrom+    enumFromThen        = boundedEnumFromThen++instance Integral Int24 where+    quot    x@(I24# x#) y@(I24# y#)+        | y == 0                     = divZeroError+        | x == minBound && y == (-1) = overflowError+        | otherwise                  = I24# (narrow24Int# (x# `quotInt#` y#))+    rem     x@(I24# x#) y@(I24# y#)+        | y == 0                     = divZeroError+        | x == minBound && y == (-1) = overflowError+        | otherwise                  = I24# (narrow24Int# (x# `remInt#` y#))+    div     x@(I24# x#) y@(I24# y#)+        | y == 0                     = divZeroError+        | x == minBound && y == (-1) = overflowError+        | otherwise                  = I24# (narrow24Int# (x# `divInt#` y#))+    mod     x@(I24# x#) y@(I24# y#)+        | y == 0                     = divZeroError+        | x == minBound && y == (-1) = overflowError+        | otherwise                  = I24# (narrow24Int# (x# `modInt#` y#))+    quotRem x@(I24# x#) y@(I24# y#)+        | y == 0                     = divZeroError+        | x == minBound && y == (-1) = overflowError+        | otherwise                  = (I24# (narrow24Int# (x# `quotInt#` y#)),+                                        I24# (narrow24Int# (x# `remInt#` y#)))+    divMod  x@(I24# x#) y@(I24# y#)+        | y == 0                     = divZeroError+        | x == minBound && y == (-1) = overflowError+        | otherwise                  = (I24# (narrow24Int# (x# `divInt#` y#)),+                                        I24# (narrow24Int# (x# `modInt#` y#)))+    toInteger (I24# x#)              = smallInteger x#++instance Bounded Int24 where+    minBound = -0x800000+    maxBound =  0x7FFFFF++instance Ix Int24 where+    range (m,n)         = [m..n]+    unsafeIndex (m,_) i = fromIntegral i - fromIntegral m+    inRange (m,n) i     = m <= i && i <= n++instance Read Int24 where+    readsPrec p s = [(fromIntegral (x::Int), r) | (x, r) <- readsPrec p s]++instance Bits Int24 where+    {-# INLINE shift #-}+    {-# INLINE bit #-}+    {-# INLINE testBit #-}++    (I24# x#) .&.   (I24# y#)  = I24# (word2Int# (int2Word# x# `and#` int2Word# y#))+    (I24# x#) .|.   (I24# y#)  = I24# (word2Int# (int2Word# x# `or#`  int2Word# y#))+    (I24# x#) `xor` (I24# y#)  = I24# (word2Int# (int2Word# x# `xor#` int2Word# y#))+    complement (I24# x#)       = I24# (word2Int# (not# (int2Word# x#)))+    (I24# x#) `shift` (I# i#)+        | isTrue# (i# >=# 0#)  = I24# (narrow24Int# (x# `iShiftL#` i#))+        | otherwise            = I24# (x# `iShiftRA#` negateInt# i#)+    (I24# x#) `shiftL`       (I# i#) = I24# (narrow24Int# (x# `iShiftL#` i#))+    (I24# x#) `unsafeShiftL` (I# i#) = I24# (narrow24Int# (x# `uncheckedIShiftL#` i#))+    (I24# x#) `shiftR`       (I# i#) = I24# (x# `iShiftRA#` i#)+    (I24# x#) `unsafeShiftR` (I# i#) = I24# (x# `uncheckedIShiftRA#` i#)+    (I24# x#) `rotate` i+        | isTrue# (i'# ==# 0#) = I24# x#+        | otherwise = I24# (narrow24Int# (word2Int# ((x'# `uncheckedShiftL#` i'#) `or#`+                                         (x'# `uncheckedShiftRL#` (24# -# i'#)))))+      where+        !x'# = narrow24Word# (int2Word# x#)+        !(I# i'#) = i `mod` 24+    bitSizeMaybe i             = Just (finiteBitSize i)+    bitSize                    = finiteBitSize+    isSigned _                 = True+    popCount (I24# x#)         = I# (word2Int# (popCnt24# (int2Word# x#)))+    bit                        = bitDefault+    testBit                    = testBitDefault++instance FiniteBits Int24 where+    finiteBitSize _ = 24+#if MIN_VERSION_base(4,8,0)+    countLeadingZeros  (I24# x#) = I# (word2Int# (clz24# (int2Word# x#)))+    countTrailingZeros (I24# x#) = I# (word2Int# (ctz24# (int2Word# x#)))+#endif++{-# RULES+"fromIntegral/Word8->Int24"   fromIntegral = \(W8# x#) -> I24# (word2Int# x#)+"fromIntegral/Word16->Int24"  fromIntegral = \(W16# x#) -> I24# (word2Int# x#)+"fromIntegral/Int8->Int24"    fromIntegral = \(I8# x#) -> I24# x#+"fromIntegral/Int16->Int24"   fromIntegral = \(I16# x#) -> I24# x#+"fromIntegral/Int24->Int24"   fromIntegral = id :: Int24 -> Int24+"fromIntegral/a->Int24"       fromIntegral = \x -> case fromIntegral x of I# x# -> I24# (narrow24Int# x#)+"fromIntegral/Int24->a"       fromIntegral = \(I24# x#) -> fromIntegral (I# x#)+  #-}++{-# RULES+"properFraction/Float->(Int24,Float)"+    properFraction = \x ->+                      case properFraction x of {+                        (n, y) -> ((fromIntegral :: Int -> Int24) n, y :: Float) }+"truncate/Float->Int24"+    truncate = (fromIntegral :: Int -> Int24) . (truncate :: Float -> Int)+"floor/Float->Int24"+    floor    = (fromIntegral :: Int -> Int24) . (floor :: Float -> Int)+"ceiling/Float->Int24"+    ceiling  = (fromIntegral :: Int -> Int24) . (ceiling :: Float -> Int)+"round/Float->Int24"+    round    = (fromIntegral :: Int -> Int24) . (round  :: Float -> Int)+  #-}++{-# RULES+"properFraction/Double->(Int24,Double)"+    properFraction = \x ->+                      case properFraction x of {+                        (n, y) -> ((fromIntegral :: Int -> Int24) n, y :: Double) }+"truncate/Double->Int24"+    truncate = (fromIntegral :: Int -> Int24) . (truncate :: Double -> Int)+"floor/Double->Int24"+    floor    = (fromIntegral :: Int -> Int24) . (floor :: Double -> Int)+"ceiling/Double->Int24"+    ceiling  = (fromIntegral :: Int -> Int24) . (ceiling :: Double -> Int)+"round/Double->Int24"+    round    = (fromIntegral :: Int -> Int24) . (round  :: Double -> Int)+  #-}++instance Storable Int24 where+  sizeOf _ = 3+  alignment _ = 3+  peek p = fmap fromIntegral $ peek ((castPtr p) :: Ptr Word24)+  poke p v = poke (castPtr p :: Ptr Word24) (fromIntegral v)
+ src/Data/TLSSetting.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE CPP #-}++-- | Helpers for setting up a tls connection with @tls@ package,+-- for further customization, please refer to @tls@ package.+--+-- Note, functions in this module will throw error if can't load certificates or CA store.+--+module Data.TLSSetting+    ( -- * Choose a CAStore+      TrustedCAStore(..)+      -- * Make TLS settings+    , makeClientParams+    , makeClientParams'+    , makeServerParams+    , makeServerParams'+      -- * Internal+    , mozillaCAStorePath+    ) where++import qualified Data.ByteString            as B+import qualified Data.PEM                   as X509+import qualified Data.X509                  as X509+import qualified Data.X509.CertificateStore as X509+import qualified Network.TLS                as TLS+import qualified Network.TLS.Extra          as TLS+import           Paths_mysql_haskell          (getDataFileName)+import qualified System.X509                as X509++#if !MIN_VERSION_tls(2,1,4)+import           Data.Default.Class         (def)+#endif++-- | The whole point of TLS is that: a peer should have already trusted+-- some certificates, which can be used for validating other peer's certificates.+-- if the certificates sent by other side form a chain. and one of them is issued+-- by one of 'TrustedCAStore', Then the peer will be trusted.+--+data TrustedCAStore+    = SystemCAStore                   -- ^ provided by your operating system.+    | MozillaCAStore                  -- ^ provided by <https://curl.haxx.se/docs/caextract.html Mozilla>.+    | CustomCAStore FilePath          -- ^ provided by your self, the CA file can contain multiple certificates.+  deriving (Show, Eq)++-- | Get the built-in mozilla CA's path.+mozillaCAStorePath :: IO FilePath+mozillaCAStorePath = getDataFileName "mozillaCAStore.pem"++makeCAStore :: TrustedCAStore -> IO X509.CertificateStore+makeCAStore SystemCAStore       = X509.getSystemCertificateStore+makeCAStore MozillaCAStore      = makeCAStore . CustomCAStore =<< mozillaCAStorePath+makeCAStore (CustomCAStore fp)  = do+    bs <- B.readFile fp+    let pems = case X509.pemParseBS bs of+          Right pms -> pms+          Left err -> error err+    case mapM (X509.decodeSignedCertificate . X509.pemContent) pems of+        Right cas -> return (X509.makeCertificateStore cas)+        Left err  -> error err++-- | make a simple tls 'TLS.ClientParams' that will validate server and use tls connection+-- without providing client's own certificate. suitable for connecting server which don't+-- validate clients.+--+-- we defer setting of 'TLS.clientServerIdentification' to connecting phase.+--+-- Note, tls's default validating method require server has v3 certificate.+-- you can use openssl's V3 extension to issue such a certificate. or change 'TLS.ClientParams'+-- before connecting.+--+makeClientParams :: TrustedCAStore          -- ^ trusted certificates.+                 -> IO TLS.ClientParams+makeClientParams tca = do+    caStore <- makeCAStore tca+    return (TLS.defaultParamsClient "" B.empty)+        {   TLS.clientSupported = defaultSupported' { TLS.supportedCiphers = TLS.ciphersuite_default }+        ,   TLS.clientShared    = defaultShared'+            {   TLS.sharedCAStore         = caStore+            ,   TLS.sharedValidationCache = defaultValidationCache'+            }+        }++-- | make a simple tls 'TLS.ClientParams' that will validate server and use tls connection+-- while providing client's own certificate as well. suitable for connecting server which+-- validate clients.+--+-- Also only accept v3 certificate.+--+makeClientParams' :: FilePath       -- ^ public certificate (X.509 format).+                  -> [FilePath]     -- ^ chain certificates (X.509 format).+                                    --   the root of your certificate chain should be+                                    --   already trusted by server, or tls will fail.+                  -> FilePath       -- ^ private key associated.+                  -> TrustedCAStore -- ^ trusted certificates.+                  -> IO TLS.ClientParams+makeClientParams' pub certs priv tca = do+    p <- makeClientParams tca+    c <- TLS.credentialLoadX509Chain pub certs priv+    case c of+        Right c' ->+            return p+                {   TLS.clientShared = (TLS.clientShared p)+                    {+                        TLS.sharedCredentials = TLS.Credentials [c']+                    }+                }+        Left err -> error err++-- | make a simple tls 'TLS.ServerParams' without validating client's certificate.+--+makeServerParams :: FilePath        -- ^ public certificate (X.509 format).+                 -> [FilePath]      -- ^ chain certificates (X.509 format).+                                    --   the root of your certificate chain should be+                                    --   already trusted by client, or tls will fail.+                 -> FilePath        -- ^ private key associated.+                 -> IO TLS.ServerParams+makeServerParams pub certs priv = do+    c <- TLS.credentialLoadX509Chain pub certs priv+    case c of+        Right c'@(X509.CertificateChain c'', _) ->+            return defaultServerParams'+                {   TLS.serverCACertificates =  c''+                ,   TLS.serverShared = defaultShared'+                    {+                        TLS.sharedCredentials = TLS.Credentials [c']+                    }+                ,   TLS.serverSupported = defaultSupported' { TLS.supportedCiphers = TLS.ciphersuite_strong }+                }+        Left err -> error err++-- | make a tls 'TLS.ServerParams' that also validating client's certificate.+--+makeServerParams' :: FilePath       -- ^ public certificate (X.509 format).+                  -> [FilePath]     -- ^ chain certificates (X.509 format).+                  -> FilePath       -- ^ private key associated.+                  -> TrustedCAStore -- ^ server will use these certificates to validate clients.+                  -> IO TLS.ServerParams+makeServerParams' pub certs priv tca = do+    caStore <- makeCAStore tca+    p <- makeServerParams pub certs priv+    return p+        {   TLS.serverWantClientCert = True+        ,   TLS.serverShared = (TLS.serverShared p)+            {   TLS.sharedCAStore = caStore+            }+        }++-- Compatibility shims for tls < 2.1.4 vs >= 2.1.4+#if MIN_VERSION_tls(2,1,4)+defaultServerParams' :: TLS.ServerParams+defaultServerParams' = TLS.defaultParamsServer++defaultShared' :: TLS.Shared+defaultShared' = TLS.defaultShared++defaultSupported' :: TLS.Supported+defaultSupported' = TLS.defaultSupported++defaultValidationCache' :: TLS.ValidationCache+defaultValidationCache' = TLS.defaultValidationCache+#else+defaultServerParams' :: TLS.ServerParams+defaultServerParams' = def++defaultShared' :: TLS.Shared+defaultShared' = def++defaultSupported' :: TLS.Supported+defaultSupported' = def++defaultValidationCache' :: TLS.ValidationCache+defaultValidationCache' = def+#endif
+ src/Data/Word/Word24.hs view
@@ -0,0 +1,285 @@+{-# OPTIONS_GHC -Wno-inline-rule-shadowing #-}++{-# LANGUAGE BangPatterns      #-}+{-# LANGUAGE CPP               #-}+{-# LANGUAGE MagicHash         #-}+{-# LANGUAGE NoImplicitPrelude #-}++#if !MIN_VERSION_base(4,8,0)+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE StandaloneDeriving #-}+#endif++-- |+-- Module      : Data.Word.Word24+-- License     : see  src/Data/LICENSE+-- Stability   : experimental+-- Portability : non-portable (GHC Extensions)++-- Provide a 24-bit unsigned integral type: 'Word24', analagous to Word8,+-- Word16, etc.+--++module Data.Word.Word24 (+  -- * Word24 type+    Word24(..)+  , byteSwap24+  , byteSwap24#+  -- * Internal helpers+  , narrow24Word#+#if MIN_VERSION_base(4,8,0)+  , clz24#+  , ctz24#+#endif+  , popCnt24#+  )++where++import           Data.Bits+import           Data.Data+import           Data.Maybe+import           Foreign.Storable++import           GHC.Arr+import           GHC.Base+import           GHC.Enum+import           GHC.Num hiding (integerToWord)+import           GHC.Ptr+import           GHC.Read+import           GHC.Real+import           GHC.Show+import           GHC.Word.Compat+import           GHC.Integer (smallInteger, integerToWord)++import           Control.DeepSeq++#if !MIN_VERSION_base(4,8,0)+import           Data.Typeable+#endif++------------------------------------------------------------------------++-- Word24 is represented in the same way as Word.  Operations may assume and+-- must ensure that it holds only values in its logical range.++-- | 24-bit unsigned integer type+--+data Word24 = W24# Word# deriving (Eq, Ord)++#if !MIN_VERSION_base(4,8,0)+deriving instance Typeable Word24+#endif++instance NFData Word24 where rnf !_ = ()++word24Type :: DataType+word24Type = mkIntType "Data.Word.Word24.Word24"++instance Data Word24 where+  toConstr x = mkIntegralConstr word24Type x+  gunfold _ z c = case constrRep c of+                    (IntConstr x) -> z (fromIntegral x)+                    _ -> error $ "Data.Data.gunfold: Constructor " ++ show c+                                 ++ " is not of type Word24."+  dataTypeOf _ = word24Type++-- | narrowings represented as primop 'and#' in GHC.+narrow24Word# :: Word# -> Word#+narrow24Word# = and# 0xFFFFFF##++#if MIN_VERSION_base(4,8,0)+-- | count leading zeros+--+clz24# :: Word# -> Word#+clz24# w# = clz32# (narrow24Word# w#) `minusWord#` 8##++-- | count trailing zeros+--+ctz24# :: Word# -> Word#+ctz24# w# = ctz# (w# `or#` 0x1000000##)+#endif++-- | the number of set bits+--+popCnt24# :: Word# -> Word#+popCnt24# w# = popCnt# (narrow24Word# w#)++instance Show Word24 where+  showsPrec p x = showsPrec p (fromIntegral x :: Int)++instance Num Word24 where+  (W24# x#) + (W24# y#) = W24# (narrow24Word# (x# `plusWord#` y#))+  (W24# x#) - (W24# y#) = W24# (narrow24Word# (x# `minusWord#` y#))+  (W24# x#) * (W24# y#) = W24# (narrow24Word# (x# `timesWord#` y#))+  negate (W24# x#)      = W24# (narrow24Word# (int2Word# (negateInt# (word2Int# x#))))+  abs x                 = x+  signum 0              = 0+  signum _              = 1+  fromInteger i         = W24# (narrow24Word# (integerToWord i))++instance Real Word24 where+  toRational x = toInteger x % 1++instance Enum Word24 where+  succ x+    | x /= maxBound  = x + 1+    | otherwise      = succError "Word24"+  pred x+    | x /= minBound  = x - 1+    | otherwise      = predError "Word24"+  toEnum i@(I# i#)+    | i >= 0 && i <= fromIntegral (maxBound :: Word24)+                     = W24# (int2Word# i#)+    | otherwise      = toEnumError "Word24" i (minBound::Word24, maxBound::Word24)+  fromEnum (W24# x#) = I# (word2Int# x#)+  enumFrom           = boundedEnumFrom+  enumFromThen       = boundedEnumFromThen++instance Integral Word24 where+  quot (W24# x#) y@(W24# y#)+    | y /= 0                 = W24# (x# `quotWord#` y#)+    | otherwise              = divZeroError+  rem (W24# x#) y@(W24# y#)+    | y /= 0                 = W24# (x# `remWord#` y#)+    | otherwise              = divZeroError+  div (W24# x#) y@(W24# y#)+    | y /= 0                 = W24# (x# `quotWord#` y#)+    | otherwise              = divZeroError+  mod (W24# x#) y@(W24# y#)+    | y /= 0                 = W24# (x# `remWord#` y#)+    | otherwise              = divZeroError+  quotRem (W24# x#) y@(W24# y#)+    | y /= 0                 = (W24# (x# `quotWord#` y#), W24# (x# `remWord#` y#))+    | otherwise              = divZeroError+  divMod (W24# x#) y@(W24# y#)+    | y /= 0                 = (W24# (x# `quotWord#` y#), W24# (x# `remWord#` y#))+    | otherwise              = divZeroError+  toInteger (W24# x#)        = smallInteger (word2Int# x#)++instance Bounded Word24 where+  minBound = 0+  maxBound = 0xFFFFFF++instance Ix Word24 where+  range (m,n)         = [m..n]+  unsafeIndex (m,_) i = fromIntegral (i - m)+  inRange (m,n) i     = m <= i && i <= n++instance Read Word24 where+  readsPrec p s = [(fromIntegral (x::Int), r) | (x, r) <- readsPrec p s]++instance Bits Word24 where+    {-# INLINE shift #-}+    {-# INLINE bit #-}+    {-# INLINE testBit #-}++    (W24# x#) .&.   (W24# y#)  = W24# (x# `and#` y#)+    (W24# x#) .|.   (W24# y#)  = W24# (x# `or#`  y#)+    (W24# x#) `xor` (W24# y#)  = W24# (x# `xor#` y#)+    complement (W24# x#)       = W24# (x# `xor#` mb#) where !(W24# mb#) = maxBound+    (W24# x#) `shift` (I# i#)+        | isTrue# (i# >=# 0#)  = W24# (narrow24Word# (x# `shiftL#` i#))+        | otherwise            = W24# (x# `shiftRL#` negateInt# i#)+    (W24# x#) `shiftL` (I# i#)       = W24# (narrow24Word# (x# `shiftL#` i#))+    (W24# x#) `unsafeShiftL` (I# i#) =+        W24# (narrow24Word# (x# `uncheckedShiftL#` i#))+    (W24# x#) `shiftR`       (I# i#) = W24# (x# `shiftRL#` i#)+    (W24# x#) `unsafeShiftR` (I# i#) = W24# (x# `uncheckedShiftRL#` i#)+    (W24# x#) `rotate`       i+        | isTrue# (i'# ==# 0#) = W24# x#+        | otherwise  = W24# (narrow24Word# ((x# `uncheckedShiftL#` i'#) `or#`+                                            (x# `uncheckedShiftRL#` (24# -# i'#))))+      where+        !(I# i'#) = i `mod` 24+    bitSizeMaybe i            = Just (finiteBitSize i)+    bitSize                   = finiteBitSize+    isSigned _                = False+    popCount (W24# x#)        = I# (word2Int# (popCnt24# x#))+    bit                       = bitDefault+    testBit                   = testBitDefault++instance FiniteBits Word24 where+    finiteBitSize _ = 24+#if MIN_VERSION_base(4,8,0)+    countLeadingZeros  (W24# x#) = I# (word2Int# (clz24# x#))+    countTrailingZeros (W24# x#) = I# (word2Int# (ctz24# x#))+#endif++-- | Swap bytes in 'Word24'.+--+byteSwap24 :: Word24 -> Word24+byteSwap24 (W24# w#) = W24# (byteSwap24# w#)++byteSwap24# :: Word# -> Word#+byteSwap24# w# = let byte0 = uncheckedShiftL# (and# w# 0x0000ff##) 16#+                     byte1 = and# w# 0x00ff00##+                     byte2 = uncheckedShiftRL# (and# w# 0xff0000##) 16#+                 in byte0 `or#` byte1 `or#` byte2++{-# RULES+"fromIntegral/Word8->Word24"    fromIntegral = \(W8# x#) -> W24# x#+"fromIntegral/Word16->Word24"   fromIntegral = \(W16# x#) -> W24# x#+"fromIntegral/Word24->Word24"   fromIntegral = id :: Word24 -> Word24+"fromIntegral/Word24->Integer"  fromIntegral = toInteger :: Word24 -> Integer+"fromIntegral/a->Word24"        fromIntegral = \x -> case fromIntegral x of W# x# -> W24# (narrow24Word# x#)+"fromIntegral/Word24->a"        fromIntegral = \(W24# x#) -> fromIntegral (W# x#)+  #-}++{-# RULES+"properFraction/Float->(Word24,Float)"+    properFraction = \x ->+                      case properFraction x of {+                        (n, y) -> ((fromIntegral :: Int -> Word24) n, y :: Float) }+"truncate/Float->Word24"+    truncate = (fromIntegral :: Int -> Word24) . (truncate :: Float -> Int)+"floor/Float->Word24"+    floor    = (fromIntegral :: Int -> Word24) . (floor :: Float -> Int)+"ceiling/Float->Word24"+    ceiling  = (fromIntegral :: Int -> Word24) . (ceiling :: Float -> Int)+"round/Float->Word24"+    round    = (fromIntegral :: Int -> Word24) . (round  :: Float -> Int)+  #-}++{-# RULES+"properFraction/Double->(Word24,Double)"+    properFraction = \x ->+                      case properFraction x of {+                        (n, y) -> ((fromIntegral :: Int -> Word24) n, y :: Double) }+"truncate/Double->Word24"+    truncate = (fromIntegral :: Int -> Word24) . (truncate :: Double -> Int)+"floor/Double->Word24"+    floor    = (fromIntegral :: Int -> Word24) . (floor :: Double -> Int)+"ceiling/Double->Word24"+    ceiling  = (fromIntegral :: Int -> Word24) . (ceiling :: Double -> Int)+"round/Double->Word24"+    round    = (fromIntegral :: Int -> Word24) . (round  :: Double -> Int)+  #-}++readWord24OffPtr :: Ptr Word24 -> IO Word24+readWord24OffPtr p = do+  let p' = castPtr p :: Ptr Word8+  w1 <- peekElemOff p' 0+  w2 <- peekElemOff p' 1+  w3 <- peekElemOff p' 2+  let w1' = (fromIntegral :: (Word8 -> Word24)) w1+      w2' = (fromIntegral :: (Word8 -> Word24)) w2+      w3' = (fromIntegral :: (Word8 -> Word24)) w3+      w = w1' .|. (w2' `shiftL` 8) .|. (w3' `shiftL` 16)+  return w++writeWord24ToPtr :: Ptr Word24 -> Word24 -> IO ()+writeWord24ToPtr p v = do+    let w1 = fromIntegral (v .&. 0x0000FF) :: Word8+        w2 = fromIntegral ((v .&. 0x00FF00) `shiftR` 8) :: Word8+        w3 = fromIntegral ((v .&. 0xFF0000) `shiftR` 16) :: Word8+    pokeByteOff p 0 w1+    pokeByteOff p 1 w2+    pokeByteOff p 2 w3++instance Storable Word24 where+  sizeOf _    = 3+  alignment _ = 3+  peek        = readWord24OffPtr+  poke        = writeWord24ToPtr+
+ src/Database/MySQL/Base.hs view
@@ -0,0 +1,327 @@+{-|+Module      : Database.MySQL.Base+Description : Prelude of mysql-haskell+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++This module provide common MySQL operations,++NOTEs on 'Exception's: This package use 'Exception' to deal with unexpected situations,+but you shouldn't try to catch them if you don't have a recovery plan,+for example: there's no meaning to catch a 'ERRException' during authentication unless you want to try different passwords.+By using this library you will meet:++    * 'NetworkException':  underline network is broken.+    * 'UnconsumedResultSet':  you should consume previous resultset before sending new command.+    * 'ERRException':  you receive a 'ERR' packet when you shouldn't.+    * 'UnexpectedPacket':  you receive a unexpected packet when you shouldn't.+    * 'DecodePacketException': there's a packet we can't decode.+    * 'WrongParamsCount': you're giving wrong number of params to 'renderParams'.++Both 'UnexpectedPacket' and 'DecodePacketException' may indicate a bug of this library rather your code, so please report!++-}+module Database.MySQL.Base+    ( -- * Setting up and control connection+      MySQLConn+    , ConnectInfo(..)+    , defaultConnectInfo+    , defaultConnectInfoMB4+    , connect+    , connectDetail+    , connectUnixSocket+    , connectUnixSocketDetail+    , close+    , ping+      -- * Direct query+    , execute+    , executeMany+    , executeMany_+    , execute_+    , query_+    , queryVector_+    , query+    , queryVector+      -- * Prepared query statement+    , prepareStmt+    , prepareStmtDetail+    , executeStmt+    , queryStmt+    , queryStmtVector+    , closeStmt+    , resetStmt+      -- * Helpers+    , withTransaction+    , QueryParam(..)+    , Param (..)+    , Query(..)+    , renderParams+    , command+    , Stream.skipToEof+      -- * Exceptions+    , NetworkException(..)+    , UnconsumedResultSet(..)+    , ERRException(..)+    , UnexpectedPacket(..)+    , DecodePacketException(..)+    , WrongParamsCount(..)+      -- * MySQL protocol+    , module  Database.MySQL.Protocol.Auth+    , module  Database.MySQL.Protocol.Command+    , module  Database.MySQL.Protocol.ColumnDef+    , module  Database.MySQL.Protocol.Packet+    , module  Database.MySQL.Protocol.MySQLValue+    ) where++import           Control.Exception                  (mask, onException, throwIO)+import           Control.Monad+import qualified Data.ByteString.Lazy               as L+import           Data.IORef                         (writeIORef)+import           Database.MySQL.Connection+import           Database.MySQL.Protocol.Auth+import           Database.MySQL.Protocol.ColumnDef+import           Database.MySQL.Protocol.Command+import           Database.MySQL.Protocol.MySQLValue+import           Database.MySQL.Protocol.Packet++import           Database.MySQL.Query+import           System.IO.Streams                  (InputStream)+import qualified System.IO.Streams                  as Stream+import qualified Data.Vector                        as V++--------------------------------------------------------------------------------++-- | Execute a MySQL query with parameters which don't return a result-set.+--+-- The query may contain placeholders @?@, for filling up parameters, the parameters+-- will be escaped before get filled into the query, please DO NOT enable @NO_BACKSLASH_ESCAPES@,+-- and you should consider using prepared statement if this's not an one shot query.+--+execute :: QueryParam p => MySQLConn -> Query -> [p] -> IO OK+execute conn qry params = execute_ conn (renderParams qry params)++{-# SPECIALIZE execute :: MySQLConn -> Query -> [MySQLValue] -> IO OK #-}+{-# SPECIALIZE execute :: MySQLConn -> Query -> [Param]      -> IO OK #-}++-- | Execute a multi-row query which don't return result-set.+--+-- Leverage MySQL's multi-statement support to do batch insert\/update\/delete,+-- you may want to use 'withTransaction' to make sure it's atomic, and+-- use @sum . map okAffectedRows@ to get all affected rows count.+--+-- @since 0.2.0.0+--+executeMany :: QueryParam p => MySQLConn -> Query -> [[p]] -> IO [OK]+executeMany conn@(MySQLConn is os _ _) qry paramsList = do+    guardUnconsumed conn+    let qry' = L.intercalate ";" $ map (fromQuery . renderParams qry) paramsList+    writeCommand (COM_QUERY qry') os+    mapM (\ _ -> waitCommandReply is) paramsList++{-# SPECIALIZE executeMany :: MySQLConn -> Query -> [[MySQLValue]] -> IO [OK] #-}+{-# SPECIALIZE executeMany :: MySQLConn -> Query -> [[Param]]      -> IO [OK] #-}++-- | Execute multiple querys (without param) which don't return result-set.+--+-- This's useful when your want to execute multiple SQLs without params, e.g. from a+-- SQL dump, or a table migration plan.+--+-- @since 0.8.4.0+--+executeMany_ :: MySQLConn -> Query -> IO [OK]+executeMany_ conn@(MySQLConn is os _ _) qry = do+    guardUnconsumed conn+    writeCommand (COM_QUERY (fromQuery qry)) os+    waitCommandReplys is++-- | Execute a MySQL query which don't return a result-set.+--+execute_ :: MySQLConn -> Query -> IO OK+execute_ conn (Query qry) = command conn (COM_QUERY qry)++-- | Execute a MySQL query which return a result-set with parameters.+--+-- Note that you must fully consumed the result-set before start a new query on+-- the same 'MySQLConn', or an 'UnconsumedResultSet' will be thrown.+-- if you want to skip the result-set, use 'Stream.skipToEof'.+--+query :: QueryParam p => MySQLConn -> Query -> [p] -> IO ([ColumnDef], InputStream [MySQLValue])+query conn qry params = query_ conn (renderParams qry params)++{-# SPECIALIZE query :: MySQLConn -> Query -> [MySQLValue] -> IO ([ColumnDef], InputStream [MySQLValue]) #-}+{-# SPECIALIZE query :: MySQLConn -> Query -> [Param]      -> IO ([ColumnDef], InputStream [MySQLValue]) #-}++-- | 'V.Vector' version of 'query'.+--+-- @since 0.5.1.0+--+queryVector :: QueryParam p => MySQLConn -> Query -> [p] -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue))+queryVector conn qry params = queryVector_ conn (renderParams qry params)++{-# SPECIALIZE queryVector :: MySQLConn -> Query -> [MySQLValue] -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue)) #-}+{-# SPECIALIZE queryVector :: MySQLConn -> Query -> [Param]      -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue)) #-}++-- | Execute a MySQL query which return a result-set.+--+query_ :: MySQLConn -> Query -> IO ([ColumnDef], InputStream [MySQLValue])+query_ conn@(MySQLConn is os _ consumed) (Query qry) = do+    guardUnconsumed conn+    writeCommand (COM_QUERY qry) os+    p <- readPacket is+    if isERR p+    then decodeFromPacket p >>= throwIO . ERRException+    else do+        len <- getFromPacket getLenEncInt p+        fields <- replicateM len $ (decodeFromPacket <=< readPacket) is+        _ <- readPacket is -- eof packet, we don't verify this though+        writeIORef consumed False+        rows <- Stream.makeInputStream $ do+            q <- readPacket is+            if  | isEOF q  -> writeIORef consumed True >> return Nothing+                | isERR q  -> decodeFromPacket q >>= throwIO . ERRException+                | otherwise -> Just <$> getFromPacket (getTextRow fields) q+        return (fields, rows)++-- | 'V.Vector' version of 'query_'.+--+-- @since 0.5.1.0+--+queryVector_ :: MySQLConn -> Query -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue))+queryVector_ conn@(MySQLConn is os _ consumed) (Query qry) = do+    guardUnconsumed conn+    writeCommand (COM_QUERY qry) os+    p <- readPacket is+    if isERR p+    then decodeFromPacket p >>= throwIO . ERRException+    else do+        len <- getFromPacket getLenEncInt p+        fields <- V.replicateM len $ (decodeFromPacket <=< readPacket) is+        _ <- readPacket is -- eof packet, we don't verify this though+        writeIORef consumed False+        rows <- Stream.makeInputStream $ do+            q <- readPacket is+            if  | isEOF q  -> writeIORef consumed True >> return Nothing+                | isERR q  -> decodeFromPacket q >>= throwIO . ERRException+                | otherwise -> Just <$> getFromPacket (getTextRowVector fields) q+        return (fields, rows)++-- | Ask MySQL to prepare a query statement.+--+prepareStmt :: MySQLConn -> Query -> IO StmtID+prepareStmt conn@(MySQLConn is os _ _) (Query stmt) = do+    guardUnconsumed conn+    writeCommand (COM_STMT_PREPARE stmt) os+    p <- readPacket is+    if isERR p+    then decodeFromPacket p >>= throwIO . ERRException+    else do+        StmtPrepareOK stid colCnt paramCnt _ <- getFromPacket getStmtPrepareOK p+        _ <- replicateM_ paramCnt (readPacket is)+        _ <- unless (paramCnt == 0) (void (readPacket is))  -- EOF+        _ <- replicateM_ colCnt (readPacket is)+        _ <- unless (colCnt == 0) (void (readPacket is))  -- EOF+        return stid++-- | Ask MySQL to prepare a query statement.+--+-- All details from @COM_STMT_PREPARE@ Response are returned: the 'StmtPrepareOK' packet,+-- params's 'ColumnDef', result's 'ColumnDef'.+--+prepareStmtDetail :: MySQLConn -> Query -> IO (StmtPrepareOK, [ColumnDef], [ColumnDef])+prepareStmtDetail conn@(MySQLConn is os _ _) (Query stmt) = do+    guardUnconsumed conn+    writeCommand (COM_STMT_PREPARE stmt) os+    p <- readPacket is+    if isERR p+    then decodeFromPacket p >>= throwIO . ERRException+    else do+        sOK@(StmtPrepareOK _ colCnt paramCnt _) <- getFromPacket getStmtPrepareOK p+        pdefs <- replicateM paramCnt ((decodeFromPacket <=< readPacket) is)+        _ <- unless (paramCnt == 0) (void (readPacket is))  -- EOF+        cdefs <- replicateM colCnt ((decodeFromPacket <=< readPacket) is)+        _ <- unless (colCnt == 0) (void (readPacket is))  -- EOF+        return (sOK, pdefs, cdefs)++-- | Ask MySQL to closed a query statement.+--+closeStmt :: MySQLConn -> StmtID -> IO ()+closeStmt (MySQLConn _ os _ _) stid = do+    writeCommand (COM_STMT_CLOSE stid) os++-- | Ask MySQL to reset a query statement, all previous resultset will be cleared.+--+resetStmt :: MySQLConn -> StmtID -> IO ()+resetStmt (MySQLConn is os _ consumed) stid = do+    writeCommand (COM_STMT_RESET stid) os  -- previous result-set may still be unconsumed+    p <- readPacket is+    if isERR p+    then decodeFromPacket p >>= throwIO . ERRException+    else writeIORef consumed True++-- | Execute prepared query statement with parameters, expecting no resultset.+--+executeStmt :: MySQLConn -> StmtID -> [MySQLValue] -> IO OK+executeStmt conn stid params =+  command conn (COM_STMT_EXECUTE stid params (makeNullMap params))++-- | Execute prepared query statement with parameters, expecting resultset.+--+-- Rules about 'UnconsumedResultSet' applied here too.+--+queryStmt :: MySQLConn -> StmtID -> [MySQLValue] -> IO ([ColumnDef], InputStream [MySQLValue])+queryStmt conn@(MySQLConn is os _ consumed) stid params = do+    guardUnconsumed conn+    writeCommand (COM_STMT_EXECUTE stid params (makeNullMap params)) os+    p <- readPacket is+    if isERR p+    then decodeFromPacket p >>= throwIO . ERRException+    else do+        len <- getFromPacket getLenEncInt p+        fields <- replicateM len $ (decodeFromPacket <=< readPacket) is+        _ <- readPacket is -- eof packet, we don't verify this though+        writeIORef consumed False+        rows <- Stream.makeInputStream $ do+            q <- readPacket is+            if  | isOK  q  -> Just <$> getFromPacket (getBinaryRow fields len) q+                | isEOF q  -> writeIORef consumed True >> return Nothing+                | isERR q  -> decodeFromPacket q >>= throwIO . ERRException+                | otherwise -> throwIO (UnexpectedPacket q)+        return (fields, rows)++-- | 'V.Vector' version of 'queryStmt'+--+-- @since 0.5.1.0+--+queryStmtVector :: MySQLConn -> StmtID -> [MySQLValue] -> IO (V.Vector ColumnDef, InputStream (V.Vector MySQLValue))+queryStmtVector conn@(MySQLConn is os _ consumed) stid params = do+    guardUnconsumed conn+    writeCommand (COM_STMT_EXECUTE stid params (makeNullMap params)) os+    p <- readPacket is+    if isERR p+    then decodeFromPacket p >>= throwIO . ERRException+    else do+        len <- getFromPacket getLenEncInt p+        fields <- V.replicateM len $ (decodeFromPacket <=< readPacket) is+        _ <- readPacket is -- eof packet, we don't verify this though+        writeIORef consumed False+        rows <- Stream.makeInputStream $ do+            q <- readPacket is+            if  | isOK  q  -> Just <$> getFromPacket (getBinaryRowVector fields len) q+                | isEOF q  -> writeIORef consumed True >> return Nothing+                | isERR q  -> decodeFromPacket q >>= throwIO . ERRException+                | otherwise -> throwIO (UnexpectedPacket q)+        return (fields, rows)++-- | Run querys inside a transaction, querys will be rolled back if exception arise.+--+-- @since 0.2.0.0+--+withTransaction :: MySQLConn -> IO a -> IO a+withTransaction conn procedure = mask $ \restore -> do+  _ <- execute_ conn "BEGIN"+  r <- restore procedure `onException` (execute_ conn "ROLLBACK")+  _ <- execute_ conn "COMMIT"+  pure r
+ src/Database/MySQL/BinLog.hs view
@@ -0,0 +1,214 @@+{-|+Module      : Database.MySQL.BinLog+Description : Binary protocol toolkit+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++This module provide tools for binlog listening and row based binlog decoding.+-}++module Database.MySQL.BinLog+    ( -- * binlog utilities+      SlaveID+    , BinLogTracker(..)+    , registerPesudoSlave+    , dumpBinLog+    , RowBinLogEvent(..)+    , decodeRowBinLogEvent+    -- * helpers+    , getLastBinLogTracker+    , isCheckSumEnabled+    , isSemiSyncEnabled+    -- * re-export+    , module Database.MySQL.BinLogProtocol.BinLogEvent+    , module Database.MySQL.BinLogProtocol.BinLogValue+    , module Database.MySQL.BinLogProtocol.BinLogMeta+    ) where++import           Control.Exception                         (throwIO)+import           Control.Monad+import           Data.Binary.Put+import           Data.ByteString                           (ByteString)+import           Data.IORef                                (IORef, newIORef,+                                                            readIORef,+                                                            writeIORef)+import           Data.Text.Encoding                        (encodeUtf8)+import           Data.Word+import           Database.MySQL.Base+import           Database.MySQL.BinLogProtocol.BinLogEvent+import           Database.MySQL.BinLogProtocol.BinLogMeta+import           Database.MySQL.BinLogProtocol.BinLogValue+import           Database.MySQL.Connection+import           GHC.Generics                              (Generic)+import           System.IO.Streams                         (InputStream)+import qualified System.IO.Streams                         as Stream++type SlaveID = Word32++-- | binlog filename and position to start listening.+--+data BinLogTracker = BinLogTracker+    { btFileName :: {-# UNPACK #-} !ByteString+    , btNextPos  :: {-# UNPACK #-} !Word32+    } deriving (Show, Eq, Generic)++-- | Register a pesudo slave to master, although MySQL document suggests you should call this+-- before calling 'dumpBinLog', but it seems it's not really necessary.+--+registerPesudoSlave :: MySQLConn -> SlaveID -> IO OK+registerPesudoSlave conn sid = command conn (COM_REGISTER_SLAVE sid "" "" "" 0 0 0)++-- | Setup binlog listening on given connection, during listening+-- the connection CAN NOT be used to do query, or an 'UnconsumedResultSet' will be thrown.+--+dumpBinLog :: MySQLConn               -- ^ connection to be listened+           -> SlaveID                 -- ^ a number for our pesudo slave.+           -> BinLogTracker           -- ^ binlog position+           -> Bool                    -- ^ if master support semi-ack, do we want to enable it?+                                      -- if master doesn't support, this parameter will be ignored.+           -> IO (FormatDescription, IORef ByteString, InputStream BinLogPacket)+                -- ^ 'FormatDescription', 'IORef' contains current binlog filename, 'BinLogPacket' stream.+dumpBinLog conn@(MySQLConn is wp _ consumed) sid (BinLogTracker initfn initpos) wantAck = do+    guardUnconsumed conn+    checksum <- isCheckSumEnabled conn+    when checksum $ void $ execute_ conn "SET @master_binlog_checksum = @@global.binlog_checksum"+    semiAck  <- isSemiSyncEnabled conn+    let needAck = semiAck && wantAck+    when needAck . void $ execute_ conn "SET @rpl_semi_sync_slave = 1"+    writeCommand (COM_BINLOG_DUMP initpos 0x00 sid initfn) wp+    writeIORef consumed False++    rp <- skipToPacketT (readBinLogPacket checksum needAck is) BINLOG_ROTATE_EVENT+    re <- getFromBinLogPacket getRotateEvent rp+    fref <- newIORef (rFileName re)++    p <- skipToPacketT (readBinLogPacket checksum needAck is) BINLOG_FORMAT_DESCRIPTION_EVENT+    replyAck needAck p fref wp+    fmt <- getFromBinLogPacket getFormatDescription p++    es <- Stream.makeInputStream $ do+        q <- readBinLogPacket checksum needAck is+        case q of+            Nothing   -> writeIORef consumed True >> return Nothing+            Just q' -> do when (blEventType q' == BINLOG_ROTATE_EVENT) $ do+                                e <- getFromBinLogPacket getRotateEvent q'+                                writeIORef' fref (rFileName e)+                          replyAck needAck q' fref wp+                          return q+    return (fmt, fref, es)+  where+    skipToPacketT iop typ = do+        p <- iop+        case p of+            Just p' -> do+                if blEventType p' == typ then return p' else skipToPacketT iop typ+            Nothing -> throwIO NetworkException++    replyAck needAck p fref wp' = when (needAck && blSemiAck p) $ do+        fn <- readIORef fref+        wp' (makeSemiAckPacket (blLogPos p) fn)++    makeSemiAckPacket pos fn = putToPacket 0 $ do+        putWord8 0xEF      -- semi-ack+        putWord64le pos+        putByteString fn++    readBinLogPacket checksum needAck is' = do+        p <- readPacket is'+        if  | isOK p -> Just <$> getFromPacket (getBinLogPacket checksum needAck) p+            | isEOF p -> return Nothing+            | isERR p -> decodeFromPacket p >>= throwIO . ERRException+            | otherwise -> error ("unkown package" <> show p)++-- | Row based binlog event type.+--+-- It's recommended to enable row query event before 'dumpBinLog', so that you can get+-- 'RowQueryEvent' in row based binlog(it's important for detect a table change for example),+-- more information please refer <http://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html#sysvar_binlog_rows_query_log_events sysvar_binlog_rows_query_log_events>+--+-- A 'BinLogTracker' is included so that you can roll up your own HA solutions,+-- for example, writing the tracker to zookeeper when you done with an event.+--+-- The first 'Word32' field is a timestamp present when this event is logged.+--+data RowBinLogEvent+    = RowQueryEvent  {-# UNPACK #-} !Word32 !BinLogTracker !QueryEvent'+    | RowDeleteEvent {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !DeleteRowsEvent+    | RowWriteEvent  {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !WriteRowsEvent+    | RowUpdateEvent {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !UpdateRowsEvent+  deriving (Show, Eq, Generic)++-- | decode row based event from 'BinLogPacket' stream.+decodeRowBinLogEvent :: (FormatDescription, IORef ByteString, InputStream BinLogPacket)+                     -> IO (InputStream RowBinLogEvent)+decodeRowBinLogEvent (fd', fref', is') = Stream.makeInputStream (loop fd' fref' is')+  where+    loop fd fref is = do+        p <- Stream.read is+        case p of+            Nothing -> return Nothing+            Just p' -> do+                let t = blEventType p'+                if  | t == BINLOG_ROWS_QUERY_EVENT -> do+                        tr <- track p' fref+                        e <- getFromBinLogPacket getQueryEvent' p'+                        pure (Just (RowQueryEvent (blTimestamp p') tr e))+                    | t == BINLOG_TABLE_MAP_EVENT -> do+                        tme <- getFromBinLogPacket (getTableMapEvent fd) p'+                        q <- Stream.read is+                        case q of+                            Nothing -> return Nothing+                            Just q' -> do+                                let u = blEventType q'+                                if  | u == BINLOG_WRITE_ROWS_EVENTv1 || u == BINLOG_WRITE_ROWS_EVENTv2 -> do+                                        tr <- track q' fref+                                        e <- getFromBinLogPacket' (getWriteRowEvent fd tme) q'+                                        pure (Just (RowWriteEvent (blTimestamp q') tr tme e))+                                    | u == BINLOG_DELETE_ROWS_EVENTv1 || u == BINLOG_DELETE_ROWS_EVENTv2 -> do+                                        tr <- track q' fref+                                        e <- getFromBinLogPacket' (getDeleteRowEvent fd tme) q'+                                        pure (Just (RowDeleteEvent (blTimestamp q') tr tme e))+                                    | u == BINLOG_UPDATE_ROWS_EVENTv1 || u == BINLOG_UPDATE_ROWS_EVENTv2 -> do+                                        tr <- track q' fref+                                        e <- getFromBinLogPacket' (getUpdateRowEvent fd tme) q'+                                        pure (Just (RowUpdateEvent (blTimestamp q') tr tme e))+                                    | otherwise -> loop fd fref is+                    | otherwise -> loop fd fref is++    track p fref = BinLogTracker <$> readIORef fref <*> (pure . fromIntegral . blLogPos) p++-- | Get latest master's binlog filename and position.+--+getLastBinLogTracker :: MySQLConn -> IO (Maybe BinLogTracker)+getLastBinLogTracker conn = do+    (_, is) <- query_ conn "SHOW MASTER STATUS"+    row <- Stream.read is+    Stream.skipToEof is+    case row of+        Just (MySQLText fn : MySQLInt64U pos : _) -> return . Just $ BinLogTracker (encodeUtf8 fn) (fromIntegral pos)+        _                                         -> return Nothing++-- | Return True if binlog_checksum = CRC32. Only for MySQL > 5.6+--+isCheckSumEnabled :: MySQLConn -> IO Bool+isCheckSumEnabled conn = do+    (_, is) <- query_ conn "SHOW GLOBAL VARIABLES LIKE 'binlog_checksum'"+    row <- Stream.read is+    Stream.skipToEof is+    case row of+        Just [_, MySQLText "CRC32"] -> return True+        _                           -> return False++-- | Return True if rpl_semi_sync_master_enabled = ON. Only for MySQL > 5.5+--+isSemiSyncEnabled :: MySQLConn -> IO Bool+isSemiSyncEnabled conn = do+    (_, is) <- query_ conn "SHOW VARIABLES LIKE 'rpl_semi_sync_master_enabled'"+    row <- Stream.read is+    Stream.skipToEof is+    case row of+        Just [_, MySQLText "ON"] -> return True+        _                        -> return False
+ src/Database/MySQL/BinLogProtocol/BinLogEvent.hs view
@@ -0,0 +1,297 @@+{-# OPTIONS_GHC -funbox-strict-fields #-}++{-|+Module      : Database.MySQL.BinLogProtocol.BinLogEvent+Description : Binlog event+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++Binlog event type+-}++module Database.MySQL.BinLogProtocol.BinLogEvent where++import           Control.Monad+import           Control.Monad.Loops                       (untilM)+import           Data.Binary+import           Data.Binary.Parser+import           Data.Bits+import           Data.ByteString                           (ByteString)+import qualified Data.ByteString                           as B+import qualified Data.ByteString.Lazy                      as L+import qualified Data.ByteString.Unsafe                    as B+import           Database.MySQL.BinLogProtocol.BinLogMeta+import           Database.MySQL.BinLogProtocol.BinLogValue+import           Database.MySQL.Protocol.Packet+import           Database.MySQL.Protocol.MySQLValue+import           Database.MySQL.Protocol.ColumnDef++import           Control.Exception                         (throwIO)+import           Database.MySQL.Query+import           GHC.Generics                              (Generic)++--------------------------------------------------------------------------------+-- | binlog tyoe+--+data BinLogEventType+    = BINLOG_UNKNOWN_EVENT+    | BINLOG_START_EVENT_V3+    | BINLOG_QUERY_EVENT+    | BINLOG_STOP_EVENT+    | BINLOG_ROTATE_EVENT+    | BINLOG_INTVAR_EVENT+    | BINLOG_LOAD_EVENT+    | BINLOG_SLAVE_EVENT+    | BINLOG_CREATE_FILE_EVENT+    | BINLOG_APPEND_BLOCK_EVENT+    | BINLOG_EXEC_LOAD_EVENT+    | BINLOG_DELETE_FILE_EVENT+    | BINLOG_NEW_LOAD_EVENT+    | BINLOG_RAND_EVENT+    | BINLOG_USER_VAR_EVENT+    | BINLOG_FORMAT_DESCRIPTION_EVENT+    | BINLOG_XID_EVENT+    | BINLOG_BEGIN_LOAD_QUERY_EVENT+    | BINLOG_EXECUTE_LOAD_QUERY_EVENT+    | BINLOG_TABLE_MAP_EVENT+    | BINLOG_WRITE_ROWS_EVENTv0+    | BINLOG_UPDATE_ROWS_EVENTv0+    | BINLOG_DELETE_ROWS_EVENTv0+    | BINLOG_WRITE_ROWS_EVENTv1+    | BINLOG_UPDATE_ROWS_EVENTv1+    | BINLOG_DELETE_ROWS_EVENTv1+    | BINLOG_INCIDENT_EVENT+    | BINLOG_HEARTBEAT_EVENT+    | BINLOG_IGNORABLE_EVENT+    | BINLOG_ROWS_QUERY_EVENT+    | BINLOG_WRITE_ROWS_EVENTv2+    | BINLOG_UPDATE_ROWS_EVENTv2+    | BINLOG_DELETE_ROWS_EVENTv2+    | BINLOG_GTID_EVENT+    | BINLOG_ANONYMOUS_GTID_EVENT+    | BINLOG_PREVIOUS_GTIDS_EVENT+  deriving (Show, Eq, Enum)++data BinLogPacket = BinLogPacket+    { blTimestamp :: !Word32+    , blEventType :: !BinLogEventType+    , blServerId  :: !Word32+    , blEventSize :: !Word32+    , blLogPos    :: !Word64   -- ^ for future GTID compatibility+    , blFlags     :: !Word16+    , blBody      :: !L.ByteString+    , blSemiAck   :: !Bool+    } deriving (Show, Eq)++putSemiAckResp :: Word32 -> ByteString -> Put+putSemiAckResp pos fn = put pos >> put fn++getBinLogPacket :: Bool -> Bool -> Get BinLogPacket+getBinLogPacket checksum semi = do+    _  <- getWord8     -- OK byte+    ack <- if semi+        then getWord8 >> (== 0x01) <$> getWord8+        else return False+    ts <- getWord32le+    typ <- toEnum . fromIntegral <$> getWord8+    sid <- getWord32le+    size <- getWord32le+    pos <- getWord32le+    flgs <- getWord16le+    body <- getLazyByteString (fromIntegral size - if checksum then 23 else 19)+    return (BinLogPacket ts typ sid size (fromIntegral pos) flgs body ack)++getFromBinLogPacket :: Get a -> BinLogPacket -> IO a+getFromBinLogPacket g (BinLogPacket _ _ _ _ _ _ body _ ) =+    case parseDetailLazy g body  of+        Left  (buf, offset, errmsg) -> throwIO (DecodePacketFailed buf offset errmsg)+        Right (_,   _,      r     ) -> return r++getFromBinLogPacket' :: (BinLogEventType -> Get a) -> BinLogPacket -> IO a+getFromBinLogPacket' g (BinLogPacket _ typ _ _ _ _ body _ ) =+    case parseDetailLazy (g typ) body  of+        Left  (buf, offset, errmsg) -> throwIO (DecodePacketFailed buf offset errmsg)+        Right (_,   _,      r     ) -> return r++--------------------------------------------------------------------------------++data FormatDescription = FormatDescription+    { fdVersion              :: !Word16+    , fdMySQLVersion         :: !ByteString+    , fdCreateTime           :: !Word32+    -- , eventHeaderLen :: !Word8  -- const 19+    , fdEventHeaderLenVector :: !ByteString  -- ^ a array indexed by Binlog Event Type - 1+                                             -- to extract the length of the event specific header.+    } deriving (Show, Eq, Generic)++getFormatDescription :: Get FormatDescription+getFormatDescription = FormatDescription <$> getWord16le+                                         <*> getByteString 50+                                         <*> getWord32le+                                         <*  getWord8+                                         <*> (L.toStrict <$> getRemainingLazyByteString)++eventHeaderLen :: FormatDescription -> BinLogEventType -> Word8+eventHeaderLen fd typ+    | idx < 0 || idx >= B.length vec = 0+    | otherwise = B.unsafeIndex vec idx+  where+    vec :: ByteString+    vec = fdEventHeaderLenVector fd+    idx :: Int+    idx = fromEnum typ - 1++data RotateEvent = RotateEvent+    { rPos :: !Word64, rFileName :: !ByteString } deriving (Show, Eq)++getRotateEvent :: Get RotateEvent+getRotateEvent = RotateEvent <$> getWord64le <*> getRemainingByteString++-- | This's query parser for statement based binlog's query event, it's actually+-- not used in row based binlog.+--+data QueryEvent = QueryEvent+    { qSlaveProxyId :: !Word32+    , qExecTime     :: !Word32+    , qErrCode      :: !Word16+    , qStatusVars   :: !ByteString+    , qSchemaName   :: !ByteString+    , qQuery        :: !Query+    } deriving (Show, Eq, Generic)++getQueryEvent :: Get QueryEvent+getQueryEvent = do+    pid <- getWord32le+    tim <- getWord32le+    slen <- getWord8+    ecode <- getWord16le+    vlen <- getWord16le+    svar <- getByteString (fromIntegral vlen)+    schema <- getByteString (fromIntegral slen)+    _ <- getWord8+    qry <- getRemainingLazyByteString+    return (QueryEvent pid tim ecode svar schema (Query qry))++-- | This's the query event in row based binlog.+--+data QueryEvent' = QueryEvent' { qQuery' :: !Query } deriving (Show, Eq)++getQueryEvent' :: Get QueryEvent'+getQueryEvent' = do+    _ <- getWord8+    QueryEvent' . Query <$> getRemainingLazyByteString++data TableMapEvent = TableMapEvent+    { tmTableId    :: !Word64+    , tmFlags      :: !Word16+    , tmSchemaName :: !ByteString+    , tmTableName  :: !ByteString+    , tmColumnCnt  :: !Int+    , tmColumnType :: ![FieldType]+    , tmColumnMeta :: ![BinLogMeta]+    , tmNullMap    :: !ByteString+    } deriving (Show, Eq, Generic)++getTableMapEvent :: FormatDescription -> Get TableMapEvent+getTableMapEvent fd = do+    let hlen = eventHeaderLen fd BINLOG_TABLE_MAP_EVENT+    tid <- if hlen == 6 then fromIntegral <$> getWord32le else getWord48le+    flgs <- getWord16le+    slen <- getWord8+    schema <- getByteString (fromIntegral slen)+    _ <- getWord8 -- 0x00+    tlen <- getWord8+    table <- getByteString (fromIntegral tlen)+    _ <- getWord8 -- 0x00+    cc <- getLenEncInt+    colTypBS <- getByteString cc+    let typs = map FieldType (B.unpack colTypBS)+    colMetaBS <- getLenEncBytes++    metas <- case runGetOrFail (forM typs getBinLogMeta) (L.fromStrict colMetaBS) of+        Left (_, _, errmsg) -> fail errmsg+        Right (_, _, r)     -> return r++    nullmap <- getByteString ((cc + 7) `div` 8)+    return (TableMapEvent tid flgs schema table cc typs metas nullmap)++data DeleteRowsEvent = DeleteRowsEvent+    { deleteTableId    :: !Word64+    , deleteFlags      :: !Word16+    -- , deleteExtraData   :: !RowsEventExtraData+    , deleteColumnCnt  :: !Int+    , deletePresentMap :: !BitMap+    , deleteRowData    :: ![[BinLogValue]]+    } deriving (Show, Eq, Generic)++getDeleteRowEvent :: FormatDescription -> TableMapEvent -> BinLogEventType -> Get DeleteRowsEvent+getDeleteRowEvent fd tme typ = do+    let hlen = eventHeaderLen fd typ+    tid <- if hlen == 6 then fromIntegral <$> getWord32le else getWord48le+    flgs <- getWord16le+    when (typ == BINLOG_DELETE_ROWS_EVENTv2) $ do+        extraLen <- getWord16le+        void $ getByteString (fromIntegral extraLen - 2)+    colCnt <- getLenEncInt+    let (plen, poffset) = (colCnt + 7) `quotRem` 8+    pmap <- getPresentMap plen poffset+    DeleteRowsEvent tid flgs colCnt pmap <$> untilM (getBinLogRow (tmColumnMeta tme) pmap) isEmpty++data WriteRowsEvent = WriteRowsEvent+    { writeTableId    :: !Word64+    , writeFlags      :: !Word16+    -- , writeExtraData   :: !RowsEventExtraData+    , writeColumnCnt  :: !Int+    , writePresentMap :: !BitMap+    , writeRowData    :: ![[BinLogValue]]+    } deriving (Show, Eq, Generic)++getWriteRowEvent :: FormatDescription -> TableMapEvent -> BinLogEventType -> Get WriteRowsEvent+getWriteRowEvent fd tme typ = do+    let hlen = eventHeaderLen fd typ+    tid <- if hlen == 6 then fromIntegral <$> getWord32le else getWord48le+    flgs <- getWord16le+    when (typ == BINLOG_WRITE_ROWS_EVENTv2) $ do+        extraLen <- getWord16le+        void $ getByteString (fromIntegral extraLen - 2)+    colCnt <- getLenEncInt+    let (plen, poffset) = (colCnt + 7) `quotRem` 8+    pmap <- getPresentMap plen poffset+    WriteRowsEvent tid flgs colCnt pmap <$> untilM (getBinLogRow (tmColumnMeta tme) pmap) isEmpty++data UpdateRowsEvent = UpdateRowsEvent+    { updateTableId    :: !Word64+    , updateFlags      :: !Word16+    -- , updateExtraData   :: !RowsEventExtraData+    , updateColumnCnt  :: !Int+    , updatePresentMap :: !(BitMap, BitMap)+    , updateRowData    :: ![ ([BinLogValue], [BinLogValue]) ]+    } deriving (Show, Eq, Generic)++getUpdateRowEvent :: FormatDescription -> TableMapEvent -> BinLogEventType -> Get UpdateRowsEvent+getUpdateRowEvent fd tme typ = do+    let hlen = eventHeaderLen fd typ+    tid <- if hlen == 6 then fromIntegral <$> getWord32le else getWord48le+    flgs <- getWord16le+    when (typ == BINLOG_UPDATE_ROWS_EVENTv2) $ do+        extraLen <- getWord16le+        void $ getByteString (fromIntegral extraLen - 2)+    colCnt <- getLenEncInt+    let (plen, poffset) = (colCnt + 7) `quotRem` 8+    pmap <- getPresentMap plen poffset+    pmap' <- getPresentMap plen poffset+    UpdateRowsEvent tid flgs colCnt (pmap, pmap') <$>+        untilM ((,) <$> getBinLogRow (tmColumnMeta tme) pmap <*> getBinLogRow (tmColumnMeta tme) pmap')+               isEmpty++getPresentMap :: Int -> Int -> Get BitMap+getPresentMap plen poffset = do+    pmap <- getByteString plen+    let pmap' = if B.null pmap+                then B.empty+                else B.init pmap `B.snoc` (B.last pmap .&. 0xFF `shiftR` (7 - poffset))+    pure (BitMap pmap')+
+ src/Database/MySQL/BinLogProtocol/BinLogMeta.hs view
@@ -0,0 +1,119 @@+{-# OPTIONS_GHC -funbox-strict-fields #-}++{-|+Module      : Database.MySQL.BinLogProtocol.BinLogMeta+Description : Binlog protocol column meta+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++This module provide column meta decoder for binlog protocol.++There're certain type won't appear in binlog event, and some types are compressed into 'mySQLTypeString'+, please take python version as a reference:  <https://github.com/noplay/python-mysql-replication>++You will not directly meet following 'FieldType' namely:++    * mySQLTypeDecimal+    * mySQLTypeNewdate+    * mySQLTypeEnum+    * mySQLTypeSet+    * mySQLTypeTinyBlob+    * mySQLTypeMediumBlOb+    * mySQLTypeLongBlob++-}++module Database.MySQL.BinLogProtocol.BinLogMeta where++import           Data.Binary.Get+import           Data.Bits+import           Data.Word+import           Database.MySQL.Protocol.ColumnDef++-- | An intermedia date type for decoding row-based event's values.+--+data BinLogMeta+    = BINLOG_TYPE_TINY+    | BINLOG_TYPE_SHORT+    | BINLOG_TYPE_INT24+    | BINLOG_TYPE_LONG+    | BINLOG_TYPE_LONGLONG+    | BINLOG_TYPE_FLOAT       !Word8         -- ^ size+    | BINLOG_TYPE_DOUBLE      !Word8         -- ^ size+    | BINLOG_TYPE_BIT         !Word16 !Word8 -- ^ bits, bytes+    | BINLOG_TYPE_TIMESTAMP+    | BINLOG_TYPE_DATETIME+    | BINLOG_TYPE_DATE+    | BINLOG_TYPE_TIME+    | BINLOG_TYPE_TIMESTAMP2  !Word8         -- ^ fsp+    | BINLOG_TYPE_DATETIME2   !Word8         -- ^ fsp+    | BINLOG_TYPE_TIME2       !Word8         -- ^ fsp+    | BINLOG_TYPE_YEAR+    | BINLOG_TYPE_NEWDECIMAL  !Word8 !Word8  -- ^ precision, scale+    | BINLOG_TYPE_ENUM        !Word8         -- ^ 1 or 2('Word8' or 'Word16'), enum index size+    | BINLOG_TYPE_SET         !Word16 !Word8 -- ^ bitmap bits, bytes+    | BINLOG_TYPE_BLOB        !Word8         -- ^ length size+    | BINLOG_TYPE_STRING      !Word16        -- ^ meta length(if < 256, then length is 8bit,+                                             -- if > 256 then length is 16bit)+    | BINLOG_TYPE_GEOMETRY    !Word8         -- ^ length size+  deriving (Show, Eq)++getBinLogMeta :: FieldType -> Get BinLogMeta+getBinLogMeta t+    | t == mySQLTypeTiny       = pure BINLOG_TYPE_TINY+    | t == mySQLTypeShort      = pure BINLOG_TYPE_SHORT+    | t == mySQLTypeInt24      = pure BINLOG_TYPE_INT24+    | t == mySQLTypeLong       = pure BINLOG_TYPE_LONG+    | t == mySQLTypeLongLong   = pure BINLOG_TYPE_LONGLONG+    | t == mySQLTypeFloat      = BINLOG_TYPE_FLOAT <$> getWord8+    | t == mySQLTypeDouble     = BINLOG_TYPE_DOUBLE <$> getWord8++    | t == mySQLTypeBit        = do+        byte0 <- getWord8+        byte1 <- getWord8+        let nbits = (fromIntegral byte1 `shiftL` 3) .|.  fromIntegral byte0+            nbytes = fromIntegral $ (nbits + 7) `shiftR` 3+        pure (BINLOG_TYPE_BIT nbits nbytes)++    | t == mySQLTypeTimestamp  = pure BINLOG_TYPE_TIMESTAMP+    | t == mySQLTypeDateTime   = pure BINLOG_TYPE_DATETIME+    | t == mySQLTypeDate       = pure BINLOG_TYPE_DATE+    | t == mySQLTypeTime       = pure BINLOG_TYPE_TIME+    | t == mySQLTypeTimestamp2 = BINLOG_TYPE_TIMESTAMP2 <$> getWord8+    | t == mySQLTypeDateTime2  = BINLOG_TYPE_DATETIME2 <$> getWord8+    | t == mySQLTypeTime2      = BINLOG_TYPE_TIME2 <$> getWord8+    | t == mySQLTypeYear       = pure BINLOG_TYPE_YEAR+    | t == mySQLTypeNewDecimal = BINLOG_TYPE_NEWDECIMAL <$> getWord8 <*> getWord8+    | t == mySQLTypeVarChar    = BINLOG_TYPE_STRING <$> getWord16le+    | t == mySQLTypeVarString  = BINLOG_TYPE_STRING <$> getWord16le++    | t == mySQLTypeString     = do+        byte0 <- getWord8+        byte1 <- getWord8+        -- http://bugs.mysql.com/37426+        if  byte0 > 0+        then if (byte0 .&. 0x30) /= 0x30+             then if FieldType (byte0 .|. 0x30) == mySQLTypeString+                  then let len = fromIntegral $ (byte0 .&. 0x30) `xor` 0x30+                           len' = len `shiftL` 4 .|. fromIntegral byte1+                       in pure $! BINLOG_TYPE_STRING len'+                  else let len = fromIntegral byte0 `shiftL` 8 :: Word16+                           len' = len .|. fromIntegral byte1+                       in pure $! BINLOG_TYPE_STRING len'+             else let t' = FieldType byte0+                  in if | t' == mySQLTypeSet    -> let nbits = fromIntegral byte1 `shiftL` 3+                                                       nbytes = fromIntegral $ (nbits + 7) `shiftR` 8+                                                   in pure (BINLOG_TYPE_SET nbits nbytes)+                        | t' == mySQLTypeEnum   -> pure (BINLOG_TYPE_ENUM byte1)+                        | t' == mySQLTypeString -> pure (BINLOG_TYPE_STRING (fromIntegral byte1))+                        | otherwise             -> fail $ "Database.MySQL.BinLogProtocol.BinLogMeta:\+                                                           \ impossible type inside binlog string: " ++ show t'+        else pure (BINLOG_TYPE_STRING (fromIntegral byte1))++    | t == mySQLTypeBlob       = BINLOG_TYPE_BLOB <$> getWord8+    | t == mySQLTypeGeometry   = BINLOG_TYPE_GEOMETRY <$> getWord8+    | otherwise                = fail $ "Database.MySQL.BinLogProtocol.BinLogMeta:\+                                        \ impossible type in binlog: " ++ show t
+ src/Database/MySQL/BinLogProtocol/BinLogValue.hs view
@@ -0,0 +1,325 @@+{-|+Module      : Database.MySQL.BinLogProtocol.BinLogValue+Description : Binlog protocol+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++Binlog protocol++-}++module Database.MySQL.BinLogProtocol.BinLogValue where++import           Data.Binary.Get+import           Data.Binary.Put                          ()+import           Data.Bits+import           Data.ByteString                          (ByteString)+import qualified Data.ByteString                          as B+import qualified Data.ByteString.Unsafe                   as B+import           Data.Int+import           Data.Int.Int24+import           Data.Scientific+import           Data.Word+import           Database.MySQL.BinLogProtocol.BinLogMeta+import           Database.MySQL.Protocol.MySQLValue+import           Database.MySQL.Protocol.Packet+import           GHC.Generics                             (Generic)++-- | Data type for representing binlog values.+--+-- This data type DOES NOT try to parse binlog values into detailed haskell values,+-- because you may not want to waste performance in situations like database middleware.+--+-- Due to the lack of signedness infomation in binlog meta, we cannot distinguish,+-- for example, between unsigned tiny 255 and tiny -1, so we use int to present+-- @TINY,SHORT,INT,LONG@. If you have unsigned columns, use 'fromIntegral' to convert it+-- to word to get real unsigned value back, for example, @fromIntegral (-1 :: Int) == 255 :: Word@+--+-- For above reason, we use 'Int24' to present MySQL's @INT24@ type, you can get back the+-- unsigned value using @word24@ package's 'Word24' type.+--+-- Timestamp types('BinLogTimeStamp' and 'BinLogTimeStamp2') are values converted into UTC already,+-- see 'MySQLVaule' 's note.+--+-- There's also no infomation about charset, so we use 'ByteString' to present both text+-- and blob types, if you want to get text representation back, you have to query column charset+-- infomation, and use icu or iconv to decode. IT MAY NOT BE UTF-8.+--+-- The @SET@ and @ENUM@ values are presented by their index's value and bitmap respectively,+-- if you need get the string value back, you have to perform a 'DESC tablename' to get the+-- set or enum table.+--+data BinLogValue+    = BinLogTiny       !Int8+    | BinLogShort      !Int16+    | BinLogInt24      !Int24+    | BinLogLong       !Int32+    | BinLogLongLong   !Int64+    | BinLogFloat      !Float+    | BinLogDouble     !Double+    | BinLogBit        !Word64          -- ^ a 64bit bitmap.+    | BinLogTimeStamp  !Word32          -- ^ a utc timestamp, note 0 doesn't mean @1970-01-01 00:00:00@,+                                        -- because mysql choose 0 to present '0000-00-00 00:00:00'+    | BinLogTimeStamp2 !Word32 !Word32  -- ^ like 'BinLogTimeStamp' with an addtional microseconds field.+    | BinLogDateTime   !Word16 !Word8 !Word8 !Word8 !Word8 !Word8         -- ^ YYYY MM DD hh mm ss+    | BinLogDateTime2  !Word16 !Word8 !Word8 !Word8 !Word8 !Word8 !Word32 -- ^ YYYY MM DD hh mm ss microsecond+    | BinLogDate       !Word16 !Word8 !Word8                   -- ^ YYYY MM DD+    | BinLogTime       !Word8  !Word16 !Word8 !Word8           -- ^ sign(1= non-negative, 0= negative) hh mm ss+    | BinLogTime2      !Word8  !Word16 !Word8 !Word8 !Word32   -- ^ sign(1= non-negative, 0= negative) hh mm ss microsecond+    | BinLogYear       !Word16                                 -- ^ year value, 0 stand for '0000'+    | BinLogNewDecimal !Scientific                             -- ^ sign(1= non-negative, 0= negative) integeral part, fractional part+    | BinLogEnum       !Word16                                 -- ^ enum indexing value+    | BinLogSet        !Word64                                 -- ^ set indexing 64bit bitmap.+    | BinLogBytes      !ByteString                             -- ^ all string and blob values.+    | BinLogGeometry   !ByteString+    | BinLogNull+  deriving (Show, Eq, Generic)++--------------------------------------------------------------------------------+-- | BinLog protocol decoder+--+getBinLogField :: BinLogMeta -> Get BinLogValue+getBinLogField BINLOG_TYPE_TINY                = BinLogTiny     <$> getInt8+getBinLogField BINLOG_TYPE_SHORT               = BinLogShort    <$> getInt16le+getBinLogField BINLOG_TYPE_INT24               = BinLogInt24 . fromIntegral <$> getWord24le+getBinLogField BINLOG_TYPE_LONG                = BinLogLong     <$> getInt32le+getBinLogField BINLOG_TYPE_LONGLONG            = BinLogLongLong <$> getInt64le+getBinLogField (BINLOG_TYPE_FLOAT  _         ) = BinLogFloat <$> getFloatle+getBinLogField (BINLOG_TYPE_DOUBLE _         ) = BinLogDouble <$> getDoublele+getBinLogField (BINLOG_TYPE_BIT    _    bytes) = BinLogBit <$> getBits' bytes+getBinLogField BINLOG_TYPE_TIMESTAMP           = BinLogTimeStamp <$> getWord32le++-- A integer in @YYYYMMDD@ format, for example:+-- 99991231 stand for @9999-12-31@+getBinLogField BINLOG_TYPE_DATE = do+    i <- getWord24le+    let (i', dd) = i `quotRem` 32+        (yyyy, mm) = i' `quotRem` 16+    pure (BinLogDate (fromIntegral yyyy)+                     (fromIntegral mm)+                     (fromIntegral dd))++getBinLogField (BINLOG_TYPE_TIMESTAMP2  fsp) = do+    s <- getWord32be -- big-endian here!+    ms <- fromIntegral <$> getMicroSecond fsp+    pure (BinLogTimeStamp2 s ms)++-- A integer in @YYYYMMDDhhmmss@, for example:+-- 99991231235959 stand for @9999-12-31 23:59:59@+getBinLogField BINLOG_TYPE_DATETIME = do+    i <- getWord64le+    let (yyyy, i')   = i      `quotRem` 10000000000+        (mm, i'')    = i'     `quotRem` 100000000+        (dd, i''')   = i''    `quotRem` 1000000+        (h, i'''')   = i'''   `quotRem` 10000+        (m, s)       = i''''  `quotRem` 100+    pure (BinLogDateTime (fromIntegral yyyy)+                         (fromIntegral mm)+                         (fromIntegral dd)+                         (fromIntegral h)+                         (fromIntegral m)+                         (fromIntegral s))++-- BINLOG_TYPE_DATETIME2(big endian)+--+-- 1 bit sign (used when on disk)+-- 17 bits year * 13 + month (year 0-9999, month 0-12)+-- 5 bits day (0-31)+-- 5 bits hour (0-23)+-- 6 bits minute (0-59)+-- 6 bits second (0-59)+-- (5 bytes in total)+--+-- fractional-seconds storage (size depends on meta)+--+getBinLogField (BINLOG_TYPE_DATETIME2 fsp) = do+    iPart <- getWord40be+    let yyyymm = iPart `shiftR` 22 .&. 0x01FFFF -- 0b011111111111111111+        (yyyy, mm) = yyyymm `quotRem` 13+        yyyy' = fromIntegral yyyy+        mm' = fromIntegral mm+        dd = fromIntegral $ iPart `shiftR` 17 .&. 0x1F -- 0b00011111+        h =  fromIntegral $ iPart `shiftR` 12 .&. 0x1F -- 0b00011111+        m =  fromIntegral $ iPart `shiftR` 6 .&. 0x3F  -- 0b00111111+        s =  fromIntegral $ iPart .&. 0x3F             -- 0b00111111+    ms <- fromIntegral <$> getMicroSecond fsp+    pure (BinLogDateTime2 yyyy' mm' dd h m s ms)++-- A integer in @hhmmss@ format(can be negative), for example:+-- 8385959 stand for @838:59:59@+getBinLogField BINLOG_TYPE_TIME = do+    i <- getWord24le+    let i' =  fromIntegral i :: Int24+        sign = if i' >= 0 then 1 else 0+    let (h, i'')     = i'     `quotRem` 10000+        (m, s)       = i''    `quotRem` 100+    pure (BinLogTime sign (fromIntegral (abs h))+                          (fromIntegral (abs m))+                          (fromIntegral (abs s)))++-- BINLOG_TYPE_TIME2(big endian)+--+-- 1 bit sign  (1= non-negative, 0= negative)+-- 1 bit unused (Reserved for wider hour range, e.g. for intervals)+-- 10 bit hour (0-836)+-- 6 bit minute (0-59)+-- 6 bit second (0-59)+-- (3 bytes in total)+--+-- fractional-seconds storage (size depends on meta)+--+getBinLogField (BINLOG_TYPE_TIME2 fsp) = do+    iPart <- getWord24be+    let sign = fromIntegral $ iPart `shiftR` 23+        iPart' = if sign == 0 then 0x800000 - iPart - 1 else iPart+        h = fromIntegral (iPart' `shiftR` 12) .&. 0x03FF -- 0b0000001111111111+        m = fromIntegral (iPart' `shiftR` 6) .&. 0x3F    -- 0b00111111+        s = fromIntegral iPart' .&. 0x3F               -- 0b00111111+    ms <- abs <$> getMicroSecond fsp+    let ms' = abs (fromIntegral ms :: Int)+    pure (BinLogTime2 sign h m s (fromIntegral ms'))++getBinLogField BINLOG_TYPE_YEAR                = do+    y <- getWord8+    pure $! if y == 0 then BinLogYear 0 else BinLogYear (1900 + fromIntegral y)++-- Decimal representation in binlog seems to be as follows:+--+-- 1st bit - sign such that set == +, unset == -+-- every 4 bytes represent 9 digits in big-endian order.+--+-- 80 00 00 05 1b 38 b0 60 00 means:+--+--   0x80 - positive+--   0x00000005 - 5+--   0x1b38b060 - 456700000+--   0x00       - 0+--+-- 54567000000 / 10^{10} = 5.4567+--+-- if there're < 9 digits at first, it will be compressed into suitable length words+-- following a simple lookup table.+--+getBinLogField (BINLOG_TYPE_NEWDECIMAL precision scale)+    | precision < scale = fail "NEWDECIMAL: precision must be >= scale"+    | otherwise = do+    let i = (precision - scale)+        (ucI, cI) = i `quotRem` digitsPerInteger+        (ucF, cF) = scale `quotRem` digitsPerInteger+        ucISize = fromIntegral (ucI `shiftL` 2)+        ucFSize = fromIntegral (ucF `shiftL` 2)+        cISize = fromIntegral (sizeTable `B.unsafeIndex` fromIntegral cI)+        cFSize = fromIntegral (sizeTable `B.unsafeIndex` fromIntegral cF)+        len = ucISize + cISize + ucFSize + cFSize++    buf <- getByteString len++    let fb = buf `B.unsafeIndex` 0+        sign = if fb .&. 0x80 == 0x80 then 1 else 0 :: Word8+        buf' = (fb `xor` 0x80) `B.cons` B.tail buf+        buf'' = if sign == 1 then buf'+                            else B.map (xor 0xFF) buf'++        iPart = fromIntegral (getCompressed cISize (B.unsafeTake cISize buf'')) * (blockSize ^ ucI)+              + getUncompressed ucI (B.unsafeDrop cISize buf'')++    let buf''' = B.unsafeDrop (ucISize + cISize) buf''++        fPart = getUncompressed ucF (B.unsafeTake ucFSize buf''') * (10 ^ cF)+              + fromIntegral (getCompressed cFSize (B.unsafeDrop ucFSize buf'''))++    let sci = scientific (iPart * 10 ^ scale + fPart) (negate $ fromIntegral scale)+        sci' = if sign == 0 then negate sci else sci+    pure (BinLogNewDecimal sci')+  where+    digitsPerInteger = 9+    blockSize = fromIntegral $ (10 :: Int32) ^ (9 :: Int)+    sizeTable = B.pack [0, 1, 1, 2, 2, 3, 3, 4, 4, 4]++    getCompressed :: Int -> ByteString -> Word64+    getCompressed 0 _  = 0+    getCompressed x bs = let fb = bs `B.unsafeIndex` 0+                             x' = x - 1+                         in fromIntegral fb `shiftL` (8 * x') .|. getCompressed x' (B.unsafeDrop 1 bs)++    getUncompressed :: Word8 -> ByteString -> Integer+    getUncompressed 0 _ = 0+    getUncompressed x bs = let v = getCompressed 4 (B.unsafeTake 4 bs)+                               x' = x - 1+                           in fromIntegral v * (blockSize ^ x') + getUncompressed x' (B.unsafeDrop 4 bs)+++getBinLogField (BINLOG_TYPE_ENUM size) =+    if  | size == 1 -> BinLogEnum . fromIntegral <$> getWord8+        | size == 2 -> BinLogEnum <$> getWord16be+        | otherwise -> fail $ "Database.MySQL.BinLogProtocol.BinLogValue: wrong \+                              \BINLOG_TYPE_ENUM size: " ++ show size+++getBinLogField (BINLOG_TYPE_SET _ bytes) = BinLogSet <$> getBits' bytes+getBinLogField (BINLOG_TYPE_BLOB lensize) = do+    len <- if  | lensize == 1 -> fromIntegral <$> getWord8+               | lensize == 2 -> fromIntegral <$> getWord16le+               | lensize == 3 -> fromIntegral <$> getWord24le+               | lensize == 4 -> fromIntegral <$> getWord32le+               | otherwise    -> fail $ "Database.MySQL.BinLogProtocol.BinLogValue: \+                                        \wrong BINLOG_TYPE_BLOB length size: " ++ show lensize+    BinLogBytes <$> getByteString len++getBinLogField (BINLOG_TYPE_STRING size) = do+    len <- if | size < 256 -> fromIntegral <$> getWord8+              | otherwise  -> fromIntegral <$> getWord16le+    BinLogBytes <$> getByteString len++getBinLogField (BINLOG_TYPE_GEOMETRY lensize) = do+    len <- if | lensize == 1 -> fromIntegral <$> getWord8+              | lensize == 2 -> fromIntegral <$> getWord16le+              | lensize == 3 -> fromIntegral <$> getWord24le+              | lensize == 4 -> fromIntegral <$> getWord32le+              | otherwise    -> fail $  "Database.MySQL.BinLogProtocol.BinLogValue: \+                                        \wrong BINLOG_TYPE_GEOMETRY length size: " ++ show lensize+    BinLogGeometry <$> getByteString len++getMicroSecond :: Word8 -> Get Int32+getMicroSecond 0 = pure 0+getMicroSecond 1 = (* 100000) . fromIntegral <$> getInt8+getMicroSecond 2 = (* 10000) . fromIntegral <$> getInt8+getMicroSecond 3 = (* 1000) . fromIntegral <$> getInt16be+getMicroSecond 4 = (* 100) . fromIntegral <$> getInt16be+getMicroSecond 5 = (* 10) . fromIntegral <$> getInt24be+getMicroSecond 6 = fromIntegral <$> getInt24be+getMicroSecond _ = pure 0++getBits' :: Word8 -> Get Word64+getBits' bytes = if bytes <= 8+    then getBits (fromIntegral bytes)+    else fail $  "Database.MySQL.BinLogProtocol.BinLogValue: \+                 \wrong bit length size: " ++ show bytes++--------------------------------------------------------------------------------+-- | BinLog row decoder+--+getBinLogRow :: [BinLogMeta] -> BitMap -> Get [BinLogValue]+getBinLogRow metas pmap = do+    let plen = B.foldl' (\acc word8 -> acc + popCount word8) 0 (fromBitMap pmap)+        maplen = (plen + 7) `shiftR` 3+    nullmap <- getByteString maplen+    go metas (BitMap nullmap) 0 pmap 0+  where+    go :: [BinLogMeta] -> BitMap -> Int -> BitMap -> Int -> Get [BinLogValue]+    go []     _       _       _     _    = pure []+    go (f:fs) nullmap nullpos pmap' ppos = do+        let ppos' = ppos + 1+        if isColumnSet pmap' ppos+        then do+            r <- if isColumnSet nullmap nullpos+                    then return BinLogNull+                    else getBinLogField f+            let nullpos' = nullpos + 1+            rest <- nullpos' `seq` ppos' `seq` go fs nullmap nullpos' pmap' ppos'+            return (rest `seq` (r : rest))+        else ppos' `seq` go fs nullmap nullpos pmap' ppos'+
+ src/Database/MySQL/Connection.hs view
@@ -0,0 +1,471 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE PackageImports #-}++{-|+Module      : Database.MySQL.Connection+Description : Connection managment+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++This is an internal module, the 'MySQLConn' type should not directly acessed to user.++-}++module Database.MySQL.Connection+    ( module Database.MySQL.Connection+    ) where++import           Control.Exception               (Exception, bracketOnError,+                                                  throwIO, catch, SomeException)+import           Control.Monad+import qualified Crypto.Hash                     as Crypto+import           Crypto.Hash.Algorithms          (SHA1(..))+import qualified Crypto.Number.Serialize         as Serialize+import qualified Crypto.PubKey.RSA               as RSA+import qualified Crypto.PubKey.RSA.OAEP          as OAEP+import qualified Data.ASN1.BinaryEncoding        as ASN1B+import qualified Data.ASN1.BitArray              as ASN1BA+import qualified Data.ASN1.Encoding              as ASN1E+import qualified Data.ASN1.Types                 as ASN1+import qualified Data.Binary                     as Binary+import qualified Data.Binary.Put                 as Binary+import           Data.Bits+#if MIN_VERSION_crypton(1,1,0)+import qualified "ram" Data.ByteArray             as BA+#else+import qualified "memory" Data.ByteArray          as BA+#endif+import           Data.ByteString                 (ByteString)+import qualified Data.ByteString                 as B+import qualified Data.ByteString.Lazy            as L+import qualified Data.ByteString.Unsafe          as B+import           Data.IORef                      (IORef, newIORef, readIORef,+                                                  writeIORef)+import qualified Data.PEM                        as PEM+import           Data.Typeable+import           Data.Word+import           Database.MySQL.Protocol.Auth+import           Database.MySQL.Protocol.Command+import           Database.MySQL.Protocol.Packet+import           Network.Socket                  (HostName, PortNumber)+import qualified Network.Socket                  as N+import           System.IO.Streams               (InputStream)+import qualified System.IO.Streams               as Stream+import qualified System.IO.Streams.TCP           as TCP+import qualified Data.Connection                 as TCP++--------------------------------------------------------------------------------++-- | 'MySQLConn' wrap both 'InputStream' and 'OutputStream' for MySQL 'Packet'.+--+-- You shouldn't use one 'MySQLConn' in different thread, if you do that,+-- consider protecting it with a @MVar@.+--+data MySQLConn = MySQLConn {+        mysqlRead        :: {-# UNPACK #-} !(InputStream  Packet)+    ,   mysqlWrite       :: (Packet -> IO ())+    ,   mysqlCloseSocket :: IO ()+    ,   isConsumed       :: {-# UNPACK #-} !(IORef Bool)+    }++-- | Everything you need to establish a MySQL connection.+--+-- To setup a TLS connection, use module "Database.MySQL.TLS" or "Database.MySQL.OpenSSL".+--+data ConnectInfo = ConnectInfo+    { ciHost     :: HostName+    , ciPort     :: PortNumber+    , ciDatabase :: ByteString+    , ciUser     :: ByteString+    , ciPassword :: ByteString+    , ciCharset  :: Word8+    } deriving Show++-- | A simple 'ConnectInfo' targeting localhost with @user=root@ and empty password.+--+--  Default charset is set to @utf8_general_ci@ to support older(< 5.5.3) MySQL versions,+--  but be aware this is a partial utf8 encoding, you may want to use 'defaultConnectInfoMB4'+--  instead to support full utf8 charset(emoji, etc.). You can query your server's support+--  with @SELECT id, collation_name FROM information_schema.collations ORDER BY id;@+--+defaultConnectInfo :: ConnectInfo+defaultConnectInfo = ConnectInfo "127.0.0.1" 3306 "" "root" "" utf8_general_ci++-- | 'defaultConnectInfo' with charset set to @utf8mb4_unicode_ci@+--+-- This is recommanded on any MySQL server version >= 5.5.3.+--+defaultConnectInfoMB4 :: ConnectInfo+defaultConnectInfoMB4 = ConnectInfo "127.0.0.1" 3306 "" "root" "" utf8mb4_unicode_ci++utf8_general_ci :: Word8+utf8_general_ci = 33++utf8mb4_unicode_ci :: Word8+utf8mb4_unicode_ci = 224++--------------------------------------------------------------------------------++-- | Socket buffer size.+--+-- maybe exposed to 'ConnectInfo' laster?+--+bUFSIZE :: Int+bUFSIZE = 16384++-- | Establish a MySQL connection.+--+connect :: ConnectInfo -> IO MySQLConn+connect = fmap snd . connectDetail++-- | Establish a MySQL connection with 'Greeting' back, so you can find server's version .etc.+--+connectDetail :: ConnectInfo -> IO (Greeting, MySQLConn)+connectDetail (ConnectInfo host port db user pass charset)+    = bracketOnError open TCP.close go+  where+    open  = connectWithBufferSize host port bUFSIZE+    go c  = do+        let is = TCP.source c+        is' <- decodeInputStream is+        p <- readPacket is'+        greet <- decodeFromPacket p+        let salt = greetingSalt1 greet `B.append` greetingSalt2 greet+            auth = mkAuth db user pass charset greet+        write c $ encodeToPacket 1 auth+        q <- readPacket is'+        completeAuth is' (write c) pass q (plainFullAuth salt)+        consumed <- newIORef True+        let waitNotMandatoryOK = catch+                (void (waitCommandReply is'))           -- server will either reply an OK packet+                ((\ _ -> return ()) :: SomeException -> IO ())   -- or directy close the connection+            conn = MySQLConn is'+                (write c)+                (writeCommand COM_QUIT (write c) >> waitNotMandatoryOK >> TCP.close c)+                consumed+        return (greet, conn)++    connectWithBufferSize h p bs = TCP.connectSocket h p >>= TCP.socketToConnection bs+    write c a = TCP.send c $ Binary.runPut . Binary.put $ a++-- | Connect to MySQL via a Unix domain socket.+--+connectUnixSocket :: FilePath -> ConnectInfo -> IO MySQLConn+connectUnixSocket socketPath ci = fmap snd (connectUnixSocketDetail socketPath ci)++-- | Connect to MySQL via a Unix domain socket with 'Greeting' back,+-- so you can find server's version .etc.+--+connectUnixSocketDetail :: FilePath -> ConnectInfo -> IO (Greeting, MySQLConn)+connectUnixSocketDetail socketPath (ConnectInfo _host _port db user pass charset)+    = bracketOnError open TCP.close go+  where+    open  = bracketOnError+                (N.socket N.AF_UNIX N.Stream 0)+                N.close+                (\sock -> do+                    N.connect sock (N.SockAddrUnix socketPath)+                    TCP.socketToConnection bUFSIZE (sock, N.SockAddrUnix socketPath)+                )+    go c  = do+        let is = TCP.source c+        is' <- decodeInputStream is+        p <- readPacket is'+        greet <- decodeFromPacket p+        let salt = greetingSalt1 greet `B.append` greetingSalt2 greet+            auth = mkAuth db user pass charset greet+        write c $ encodeToPacket 1 auth+        q <- readPacket is'+        completeAuth is' (write c) pass q (plainFullAuth salt)+        consumed <- newIORef True+        let waitNotMandatoryOK = catch+                (void (waitCommandReply is'))           -- server will either reply an OK packet+                ((\_ -> return ()) :: SomeException -> IO ())   -- or directy close the connection+            conn = MySQLConn is'+                (write c)+                (writeCommand COM_QUIT (write c) >> waitNotMandatoryOK >> TCP.close c)+                consumed+        return (greet, conn)++    write c a = TCP.send c $ Binary.runPut . Binary.put $ a++mkAuth :: ByteString -> ByteString -> ByteString -> Word8 -> Greeting -> Auth+mkAuth db user pass charset greet =+    let salt = greetingSalt1 greet `B.append` greetingSalt2 greet+        plugin = greetingAuthPlugin greet+        scambleBuf = scrambleForPlugin plugin salt pass+    in Auth clientCap clientMaxPacketSize charset user scambleBuf db plugin++-- | Dispatch scramble based on the authentication plugin name.+scrambleForPlugin :: ByteString -> ByteString -> ByteString -> ByteString+scrambleForPlugin plugin salt pass+    | plugin == "caching_sha2_password" = scrambleSHA256 salt pass+    | otherwise                         = scrambleSHA1 salt pass++-- | SHA1-based scramble for @mysql_native_password@.+scrambleSHA1 :: ByteString -> ByteString -> ByteString+scrambleSHA1 salt pass+    | B.null pass = B.empty+    | otherwise   = B.pack (B.zipWith xor sha1pass withSalt)+    where sha1pass = sha1 pass+          withSalt = sha1 (salt `B.append` sha1 sha1pass)+          sha1 :: ByteString -> ByteString+          sha1 = BA.convert . (Crypto.hash :: ByteString -> Crypto.Digest Crypto.SHA1)++-- | SHA256-based scramble for @caching_sha2_password@.+-- XOR(SHA256(password), SHA256(SHA256(SHA256(password)) + nonce))+scrambleSHA256 :: ByteString -> ByteString -> ByteString+scrambleSHA256 salt pass+    | B.null pass = B.empty+    | otherwise   = B.pack (B.zipWith xor sha256pass withSalt)+    where sha256pass = sha256 pass+          withSalt   = sha256 (sha256 sha256pass `B.append` salt)+          sha256 :: ByteString -> ByteString+          sha256 = BA.convert . (Crypto.hash :: ByteString -> Crypto.Digest Crypto.SHA256)++-- | Handle multi-step authentication after sending the initial auth response.+--+-- This handles OK, ERR, AuthMoreData (0x01), and AuthSwitchRequest (0xFE).+-- The @fullAuth@ callback is invoked when the server requests full authentication+-- (e.g., cleartext password over TLS).+completeAuth :: InputStream Packet       -- ^ packet input stream+             -> (Packet -> IO ())        -- ^ packet writer+             -> ByteString               -- ^ password+             -> Packet                   -- ^ the first response packet from server+             -> (Word8 -> ByteString -> (Packet -> IO ()) -> InputStream Packet -> IO ())+                                         -- ^ full auth callback (seqN, password, writer, input)+             -> IO ()+completeAuth is writePacket pass p fullAuth+    | isOK p  = return ()+    | isERR p = decodeFromPacket p >>= throwIO . ERRException+    | isAuthMoreData p = do+        let body = L.toStrict (pBody p)+        case B.index body 1 of+            0x03 -> do  -- fast auth success, read the final OK+                ok <- readPacket is+                if isOK ok+                    then return ()+                    else decodeFromPacket ok >>= throwIO . ERRException+            0x04 -> do  -- full auth required+                fullAuth (pSeqN p + 1) pass writePacket is+            _    -> throwIO (UnexpectedPacket p)+    | isAuthSwitch p = do+        -- Parse AuthSwitchRequest: 0xFE, plugin name (NUL), salt+        let body = L.toStrict (pBody p)+            rest = B.drop 1 body  -- skip 0xFE+            (newPlugin, rest') = B.break (== 0) rest+            newSalt = B.drop 1 rest'  -- skip NUL; trailing NUL may or may not be present+            -- Remove trailing NUL from salt if present+            newSalt' = if not (B.null newSalt) && B.last newSalt == 0+                       then B.init newSalt+                       else newSalt+            scrambled = scrambleForPlugin newPlugin newSalt' pass+            seqN = pSeqN p + 1+            responseBody = L.fromStrict scrambled+            responsePacket = Packet (fromIntegral (B.length scrambled)) seqN responseBody+        writePacket responsePacket+        q <- readPacket is+        completeAuth is writePacket pass q fullAuth+    | otherwise = throwIO (UnexpectedPacket p)++-- | Full auth handler for plain TCP connections using RSA encryption.+--+-- The nonce is captured via partial application at the call site:+-- @completeAuth is writePacket pass q (plainFullAuth salt)@+plainFullAuth :: ByteString -> Word8 -> ByteString -> (Packet -> IO ()) -> InputStream Packet -> IO ()+plainFullAuth nonce seqN pass writePacket is = do+    -- Request server's RSA public key+    writePacket (putToPacket seqN (Binary.putWord8 0x02))+    keyPkt <- readPacket is+    -- Key packet body: 0x01 <PEM bytes>+    let pemKey = L.toStrict (L.drop 1 (pBody keyPkt))+    doRSAAuth writePacket (pSeqN keyPkt + 1) pass nonce pemKey+    q <- readPacket is+    if isOK q then pure ()+              else decodeFromPacket q >>= throwIO . ERRException++-- | Parse a PEM-encoded SubjectPublicKeyInfo RSA public key (PKCS#8 / RFC 5480).+parseRSAPublicKey :: ByteString -> Either String RSA.PublicKey+parseRSAPublicKey pemBytes =+    either (Left . show) Right (PEM.pemParseBS pemBytes)+    >>= firstPEM+    >>= decodeDER+    >>= spkiBitString+    >>= decodeDER+    >>= rsaKey+  where+    firstPEM []    = Left "empty PEM"+    firstPEM (x:_) = Right (PEM.pemContent x)++    decodeDER bs = either (Left . show) Right (ASN1E.decodeASN1' ASN1B.DER bs)++    spkiBitString (ASN1.Start ASN1.Sequence+                   : ASN1.Start ASN1.Sequence+                   : ASN1.OID _+                   : ASN1.Null+                   : ASN1.End ASN1.Sequence+                   : ASN1.BitString bs+                   : ASN1.End ASN1.Sequence+                   : [])+        = Right (ASN1BA.bitArrayGetData bs)+    spkiBitString xs = Left ("unexpected SPKI ASN1: " ++ show xs)++    rsaKey (ASN1.Start ASN1.Sequence+            : ASN1.IntVal n+            : ASN1.IntVal e+            : ASN1.End ASN1.Sequence+            : [])+        = Right RSA.PublicKey+            { RSA.public_size = B.length (Serialize.i2osp n :: ByteString)+            , RSA.public_n    = n+            , RSA.public_e    = e+            }+    rsaKey xs = Left ("unexpected RSA key ASN1: " ++ show xs)++-- | XOR @(password ++ NUL)@ with a cyclically-extended nonce.+xorPasswordNonce :: ByteString -> ByteString -> ByteString+xorPasswordNonce pass nonce =+    let msg      = pass `B.snoc` 0x00+        nonceLen = B.length nonce+        cycled   = B.pack [nonce `B.index` (i `mod` nonceLen) | i <- [0 .. B.length msg - 1]]+    in B.pack (B.zipWith xor msg cycled)++-- | Encrypt password with the server's RSA public key and send it.+doRSAAuth :: (Packet -> IO ()) -> Word8 -> ByteString -> ByteString -> ByteString -> IO ()+doRSAAuth writePacket seqN pass nonce pemKey = do+    pubKey <- either (\e -> throwIO (userError ("RSA key parse: " ++ e))) pure+                     (parseRSAPublicKey pemKey)+    result <- OAEP.encrypt (OAEP.defaultOAEPParams SHA1) pubKey+                           (xorPasswordNonce pass nonce)+    ct <- either (\e -> throwIO (userError ("RSA encrypt: " ++ show e))) pure result+    writePacket (putToPacket seqN (Binary.putByteString ct))++data AuthException = AuthException String deriving (Typeable, Show)+instance Exception AuthException++-- | A specialized 'decodeInputStream' here for speed+decodeInputStream :: InputStream ByteString -> IO (InputStream Packet)+decodeInputStream is = Stream.makeInputStream $ do+    bs <- Stream.readExactly 4 is+    let len =  fromIntegral (bs `B.unsafeIndex` 0)+           .|. fromIntegral (bs `B.unsafeIndex` 1) `shiftL` 8+           .|. fromIntegral (bs `B.unsafeIndex` 2) `shiftL` 16+        seqN = bs `B.unsafeIndex` 3+    body <- loopRead [] len is+    return . Just $ Packet len seqN body+  where+    loopRead acc 0 _  = return $! L.fromChunks (reverse acc)+    loopRead acc k is' = do+        bs <- Stream.read is'+        case bs of Nothing -> throwIO NetworkException+                   Just bs' -> do let l = fromIntegral (B.length bs')+                                  if l >= k+                                  then do+                                      let (a, rest) = B.splitAt (fromIntegral k) bs'+                                      unless (B.null rest) (Stream.unRead rest is')+                                      return $! L.fromChunks (reverse (a:acc))+                                  else do+                                      let k' = k - l+                                      k' `seq` loopRead (bs':acc) k' is'++-- | Close a MySQL connection.+--+close :: MySQLConn -> IO ()+close (MySQLConn _ _ closeSocket _) = closeSocket++-- | Send a 'COM_PING'.+--+ping :: MySQLConn -> IO OK+ping = flip command COM_PING++--------------------------------------------------------------------------------+-- helpers++-- | Send a 'Command' which don't return a resultSet.+--+command :: MySQLConn -> Command -> IO OK+command conn@(MySQLConn is os _ _) cmd = do+    guardUnconsumed conn+    writeCommand cmd os+    waitCommandReply is+{-# INLINE command #-}++waitCommandReply :: InputStream Packet -> IO OK+waitCommandReply is = do+    p <- readPacket is+    if  | isERR p -> decodeFromPacket p >>= throwIO . ERRException+        | isOK  p -> decodeFromPacket p+        | otherwise -> throwIO (UnexpectedPacket p)+{-# INLINE waitCommandReply #-}++waitCommandReplys :: InputStream Packet -> IO [OK]+waitCommandReplys is = do+    p <- readPacket is+    if  | isERR p -> decodeFromPacket p >>= throwIO . ERRException+        | isOK  p -> do ok <- decodeFromPacket p+                        if isThereMore ok+                        then (ok :) <$> waitCommandReplys is+                        else return [ok]+        | otherwise -> throwIO (UnexpectedPacket p)+{-# INLINE waitCommandReplys #-}++readPacket :: InputStream Packet -> IO Packet+readPacket is = Stream.read is >>= maybe+    (throwIO NetworkException)+    (\ p@(Packet len _ bs) -> if len < 16777215 then return p else go len [bs])+  where+    go len acc = Stream.read is >>= maybe+        (throwIO NetworkException)+        (\ (Packet len' seqN bs) -> do+            let len'' = len + len'+                acc' = bs:acc+            if len' < 16777215+            then return (Packet len'' seqN (L.concat . reverse $ acc'))+            else len'' `seq` go len'' acc'+        )+{-# INLINE readPacket #-}++writeCommand :: Command -> (Packet -> IO ()) -> IO ()+writeCommand a writePacket = let bs = Binary.runPut (putCommand a) in+    go (L.length bs) 0 bs writePacket+  where+    go len seqN bs writePacket' = do+        if len < 16777215+        then writePacket (Packet len seqN bs)+        else do+            let (bs', rest) = L.splitAt 16777215 bs+                seqN' = seqN + 1+                len'  = len - 16777215++            writePacket (Packet 16777215 seqN bs')+            seqN' `seq` len' `seq` go len' seqN' rest writePacket'+{-# INLINE writeCommand #-}++guardUnconsumed :: MySQLConn -> IO ()+guardUnconsumed (MySQLConn _ _ _ consumed) = do+    c <- readIORef consumed+    unless c (throwIO UnconsumedResultSet)+{-# INLINE guardUnconsumed #-}++writeIORef' :: IORef a -> a -> IO ()+writeIORef' ref x = x `seq` writeIORef ref x+{-# INLINE writeIORef' #-}++--------------------------------------------------------------------------------+-- Exceptions++data NetworkException = NetworkException deriving (Typeable, Show)+instance Exception NetworkException++data UnconsumedResultSet = UnconsumedResultSet deriving (Typeable, Show)+instance Exception UnconsumedResultSet++data ERRException = ERRException ERR deriving (Typeable, Show)+instance Exception ERRException++data UnexpectedPacket = UnexpectedPacket Packet deriving (Typeable, Show)+instance Exception UnexpectedPacket+
+ src/Database/MySQL/Protocol/Auth.hs view
@@ -0,0 +1,198 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -funbox-strict-fields #-}++{-|+Module      : Database.MySQL.Protocol.Auth+Description : MySQL Auth Packets+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++Auth related packet.++-}++module Database.MySQL.Protocol.Auth where++import           Control.Monad+import           Data.Binary+import           Data.Binary.Get+import           Data.Binary.Parser+import           Data.Binary.Put+import qualified Data.ByteString                as B+import           Data.ByteString.Char8          as BC+import           Data.Bits+import           Database.MySQL.Protocol.Packet++--------------------------------------------------------------------------------+-- Authentications++#define CLIENT_LONG_PASSWORD                  0x00000001+#define CLIENT_FOUND_ROWS                     0x00000002+#define CLIENT_LONG_FLAG                      0x00000004+#define CLIENT_CONNECT_WITH_DB                0x00000008+#define CLIENT_NO_SCHEMA                      0x00000010+#define CLIENT_COMPRESS                       0x00000020+#define CLIENT_ODBC                           0x00000040+#define CLIENT_LOCAL_FILES                    0x00000080+#define CLIENT_IGNORE_SPACE                   0x00000100+#define CLIENT_PROTOCOL_41                    0x00000200+#define CLIENT_INTERACTIVE                    0x00000400+#define CLIENT_SSL                            0x00000800+#define CLIENT_IGNORE_SIGPIPE                 0x00001000+#define CLIENT_TRANSACTIONS                   0x00002000+#define CLIENT_RESERVED                       0x00004000+#define CLIENT_SECURE_CONNECTION              0x00008000+#define CLIENT_MULTI_STATEMENTS               0x00010000+#define CLIENT_MULTI_RESULTS                  0x00020000+#define CLIENT_PS_MULTI_RESULTS               0x00040000+#define CLIENT_PLUGIN_AUTH                    0x00080000+#define CLIENT_CONNECT_ATTRS                  0x00100000+#define CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA 0x00200000++data Greeting = Greeting+    { greetingProtocol :: !Word8+    , greetingVersion  :: !B.ByteString+    , greetingConnId   :: !Word32+    , greetingSalt1    :: !B.ByteString+    , greetingCaps     :: !Word32+    , greetingCharset  :: !Word8+    , greetingStatus   :: !Word16+    , greetingSalt2    :: !B.ByteString+    , greetingAuthPlugin :: !B.ByteString+    } deriving (Show, Eq)++putGreeting :: Greeting -> Put+putGreeting (Greeting pv sv cid salt1 cap charset st salt2 authPlugin) = do+    putWord8 pv+    putByteString sv+    putWord8 0x00+    putWord32le cid+    putByteString salt1+    let capL = fromIntegral cap .|. 0xFF+        capH = fromIntegral (cap `shiftR` 16) .|. 0xFF+    putWord16le capL+    putWord8 charset+    putWord16le st+    putWord16le capH+    putWord8 (fromIntegral $ B.length salt2)+    replicateM_ 10 (putWord8 0x00)+    when (cap .&. CLIENT_SECURE_CONNECTION /= 0)+        (putByteString salt2)+    when (cap .&. CLIENT_PLUGIN_AUTH /= 0)+        (putByteString authPlugin)++getGreeting :: Get Greeting+getGreeting = do+    pv <- getWord8+    sv <- getByteStringNul+    cid <- getWord32le+    salt1 <- getByteString 8+    skipN 1  -- 0x00+    capL <- getWord16le+    charset <- getWord8+    status <- getWord16le+    capH <- getWord16le+    let cap = fromIntegral capH `shiftL` 16 .|. fromIntegral capL+    _authPluginLen <- getWord8   -- this will issue an unused warning, see the notes below+    skipN 10 -- 10 * 0x00+    salt2 <- if (cap .&. CLIENT_SECURE_CONNECTION) == 0+        then pure B.empty+        else getByteStringNul   -- This is different with the MySQL document here+                                -- The doc said we should expect a MAX(13, length of auth-plugin-data - 8)+                                -- length bytes, but doing so stop us from login+                                -- anyway 'getByteStringNul' works perfectly here.++    authPlugin <- if (cap .&. CLIENT_PLUGIN_AUTH) == 0+        then pure B.empty+        else getByteStringNul++    return (Greeting pv sv cid salt1 cap charset status salt2 authPlugin)++instance Binary Greeting where+    get = getGreeting+    put = putGreeting++data Auth = Auth+    { authCaps      :: !Word32+    , authMaxPacket :: !Word32+    , authCharset   :: !Word8+    , authName      :: !ByteString+    , authPassword  :: !ByteString+    , authSchema    :: !ByteString+    , authPlugin    :: !ByteString+    } deriving (Show, Eq)++getAuth :: Get Auth+getAuth = do+    a <- getWord32le+    m <- getWord32le+    c <- getWord8+    skipN 23+    n <- getByteStringNul+    return $ Auth a m c n B.empty B.empty B.empty++putAuth :: Auth -> Put+putAuth (Auth cap m c n p s plugin) = do+    putWord32le cap+    putWord32le m+    putWord8 c+    replicateM_ 23 (putWord8 0x00)+    putByteString n >> putWord8 0x00+    putWord8 $ fromIntegral (B.length p)+    putByteString p+    putByteString s+    putWord8 0x00+    putByteString plugin+    putWord8 0x00++instance Binary Auth where+    get = getAuth+    put = putAuth++data SSLRequest = SSLRequest+    { sslReqCaps      :: !Word32+    , sslReqMaxPacket :: !Word32+    , sslReqCharset   :: !Word8+    } deriving (Show, Eq)++getSSLRequest :: Get SSLRequest+getSSLRequest = SSLRequest <$> getWord32le <*> getWord32le <*> getWord8 <* skipN 23++putSSLRequest :: SSLRequest -> Put+putSSLRequest (SSLRequest cap m c) = do+    putWord32le cap+    putWord32le m+    putWord8 c+    replicateM_ 23 (putWord8 0x00)++instance Binary SSLRequest where+    get = getSSLRequest+    put = putSSLRequest++--------------------------------------------------------------------------------+-- default Capability Flags++clientCap :: Word32+clientCap =  CLIENT_LONG_PASSWORD+                .|. CLIENT_LONG_FLAG+                .|. CLIENT_CONNECT_WITH_DB+                .|. CLIENT_IGNORE_SPACE+                .|. CLIENT_PROTOCOL_41+                .|. CLIENT_TRANSACTIONS+                .|. CLIENT_MULTI_STATEMENTS+                .|. CLIENT_MULTI_RESULTS+                .|. CLIENT_SECURE_CONNECTION+                .|. CLIENT_PLUGIN_AUTH++clientMaxPacketSize :: Word32+clientMaxPacketSize = 0x00ffffff :: Word32+++supportTLS :: Word32 -> Bool+supportTLS x = (x .&. CLIENT_SSL) /= 0++sslRequest :: Word8 -> SSLRequest+sslRequest charset = SSLRequest (clientCap .|. CLIENT_SSL) clientMaxPacketSize charset
+ src/Database/MySQL/Protocol/ColumnDef.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -funbox-strict-fields #-}++{-|+Module      : Database.MySQL.Protocol.ColumnDef+Description : MySQL field type+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++Column definition(aka. field type).++-}++module Database.MySQL.Protocol.ColumnDef where++import           Data.Binary+import           Data.Binary.Get+import           Data.Binary.Parser+import           Data.Binary.Put+import           Data.Bits                      ((.&.))+import           Data.ByteString                (ByteString)+import           Database.MySQL.Protocol.Packet++--------------------------------------------------------------------------------+--  Resultset++-- | A description of a field (column) of a table.+data ColumnDef = ColumnDef+    { -- fieldCatalog :: !ByteString              -- ^ const 'def'+      columnDB        ::  !ByteString             -- ^ Database for table.+    , columnTable     ::  !ByteString             -- ^ Table of column, if column was a field.+    , columnOrigTable ::  !ByteString             -- ^ Original table name, if table was an alias.+    , columnName      ::  !ByteString             -- ^ Name of column.+    , columnOrigName  ::  !ByteString             -- ^ Original column name, if an alias.+    , columnCharSet   ::  !Word16                 -- ^ Character set number.+    , columnLength    ::  !Word32                 -- ^ Width of column (create length).+    , columnType      ::  !FieldType+    , columnFlags     ::  !Word16                 -- ^ Div flags.+    , columnDecimals  ::  !Word8                  -- ^ Number of decimals in field.+    } deriving (Show, Eq)++getField :: Get ColumnDef+getField = ColumnDef+        <$> (skipN 4                 -- const "def"+         *> getLenEncBytes)         -- db+        <*> getLenEncBytes          -- table+        <*> getLenEncBytes          -- origTable+        <*> getLenEncBytes          -- name+        <*> getLenEncBytes          -- origName+        <*  skipN 1                  -- const 0x0c+        <*> getWord16le             -- charset+        <*> getWord32le             -- length+        <*> getFieldType            -- type+        <*> getWord16le             -- flags+        <*> getWord8                -- decimals+        <* skipN 2                   -- const 0x00 0x00+{-# INLINE getField #-}++putField :: ColumnDef -> Put+putField (ColumnDef db tbl otbl name oname charset len typ flags dec) = do+    putLenEncBytes "def"+    putLenEncBytes db+    putLenEncBytes tbl+    putLenEncBytes otbl+    putLenEncBytes name+    putLenEncBytes oname+    putWord16le charset+    putWord32le len+    putFieldType typ+    putWord16le  flags+    putWord8 dec+    putWord16le 0X0000+{-# INLINE putField #-}++instance Binary ColumnDef where+    get = getField+    {-# INLINE get #-}+    put = putField+    {-# INLINE put #-}++-- | @newtype@ around 'Word8' for represent @MySQL_TYPE@, We don't use sum type here for speed reason.+--+newtype FieldType = FieldType Word8 deriving (Show, Eq)++mySQLTypeDecimal, mySQLTypeTiny, mySQLTypeShort, mySQLTypeLong, mySQLTypeFloat :: FieldType+mySQLTypeDouble, mySQLTypeNull, mySQLTypeTimestamp, mySQLTypeLongLong, mySQLTypeInt24 :: FieldType+mySQLTypeDate, mySQLTypeTime, mySQLTypeDateTime, mySQLTypeYear, mySQLTypeNewDate, mySQLTypeVarChar :: FieldType+mySQLTypeBit, mySQLTypeTimestamp2, mySQLTypeDateTime2, mySQLTypeTime2, mySQLTypeNewDecimal :: FieldType+mySQLTypeEnum, mySQLTypeSet, mySQLTypeTinyBlob, mySQLTypeMediumBlob, mySQLTypeLongBlob :: FieldType+mySQLTypeBlob, mySQLTypeVarString, mySQLTypeString, mySQLTypeGeometry :: FieldType++mySQLTypeDecimal        = FieldType 0x00+mySQLTypeTiny           = FieldType 0x01+mySQLTypeShort          = FieldType 0x02+mySQLTypeLong           = FieldType 0x03+mySQLTypeFloat          = FieldType 0x04+mySQLTypeDouble         = FieldType 0x05+mySQLTypeNull           = FieldType 0x06+mySQLTypeTimestamp      = FieldType 0x07+mySQLTypeLongLong       = FieldType 0x08+mySQLTypeInt24          = FieldType 0x09+mySQLTypeDate           = FieldType 0x0a+mySQLTypeTime           = FieldType 0x0b+mySQLTypeDateTime       = FieldType 0x0c+mySQLTypeYear           = FieldType 0x0d+mySQLTypeNewDate        = FieldType 0x0e+mySQLTypeVarChar        = FieldType 0x0f+mySQLTypeBit            = FieldType 0x10+mySQLTypeTimestamp2     = FieldType 0x11+mySQLTypeDateTime2      = FieldType 0x12+mySQLTypeTime2          = FieldType 0x13+mySQLTypeNewDecimal     = FieldType 0xf6+mySQLTypeEnum           = FieldType 0xf7+mySQLTypeSet            = FieldType 0xf8+mySQLTypeTinyBlob       = FieldType 0xf9+mySQLTypeMediumBlob     = FieldType 0xfa+mySQLTypeLongBlob       = FieldType 0xfb+mySQLTypeBlob           = FieldType 0xfc+mySQLTypeVarString      = FieldType 0xfd+mySQLTypeString         = FieldType 0xfe+mySQLTypeGeometry       = FieldType 0xff++getFieldType :: Get FieldType+getFieldType = FieldType <$> getWord8+{-# INLINE getFieldType #-}++putFieldType :: FieldType -> Put+putFieldType (FieldType t) = putWord8 t+{-# INLINE putFieldType #-}++instance Binary FieldType where+    get = getFieldType+    {-# INLINE get #-}+    put = putFieldType+    {-# INLINE put #-}++--------------------------------------------------------------------------------+--  Field flags++#define NOT_NULL_FLAG         1+#define PRI_KEY_FLAG          2+#define UNIQUE_KEY_FLAG       4+#define MULT_KEY_FLAG         8+#define BLOB_FLAG             16+#define UNSIGNED_FLAG         32+#define ZEROFILL_FLAG         64+#define BINARY_FLAG           128+#define ENUM_FLAG             256+#define AUTO_INCREMENT_FLAG   512+#define TIMESTAMP_FLAG        1024+#define SET_FLAG              2048+#define NO_DEFAULT_VALUE_FLAG 4096+#define PART_KEY_FLAG         16384+#define NUM_FLAG              32768++flagNotNull, flagPrimaryKey, flagUniqueKey, flagMultipleKey, flagBlob, flagUnsigned, flagZeroFill :: Word16 -> Bool+flagBinary, flagEnum, flagAutoIncrement, flagTimeStamp, flagSet, flagNoDefaultValue, flagPartKey, flagNumeric :: Word16 -> Bool+flagNotNull        flags = flags .&. NOT_NULL_FLAG         == NOT_NULL_FLAG+flagPrimaryKey     flags = flags .&. PRI_KEY_FLAG          == PRI_KEY_FLAG+flagUniqueKey      flags = flags .&. UNIQUE_KEY_FLAG       == UNIQUE_KEY_FLAG+flagMultipleKey    flags = flags .&. MULT_KEY_FLAG         == MULT_KEY_FLAG+flagBlob           flags = flags .&. BLOB_FLAG             == BLOB_FLAG+flagUnsigned       flags = flags .&. UNSIGNED_FLAG         == UNSIGNED_FLAG+flagZeroFill       flags = flags .&. ZEROFILL_FLAG         == ZEROFILL_FLAG+flagBinary         flags = flags .&. BINARY_FLAG           == BINARY_FLAG+flagEnum           flags = flags .&. ENUM_FLAG             == ENUM_FLAG+flagAutoIncrement  flags = flags .&. AUTO_INCREMENT_FLAG   == AUTO_INCREMENT_FLAG+flagTimeStamp      flags = flags .&. TIMESTAMP_FLAG        == TIMESTAMP_FLAG+flagSet            flags = flags .&. SET_FLAG              == SET_FLAG+flagNoDefaultValue flags = flags .&. NO_DEFAULT_VALUE_FLAG == NO_DEFAULT_VALUE_FLAG+flagPartKey        flags = flags .&. PART_KEY_FLAG         == PART_KEY_FLAG+flagNumeric        flags = flags .&. NUM_FLAG              == NUM_FLAG
+ src/Database/MySQL/Protocol/Command.hs view
@@ -0,0 +1,107 @@+{-# OPTIONS_GHC -funbox-strict-fields #-}++{-|+Module      : Database.MySQL.Protocol.Command+Description : MySQL commands+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++Common MySQL commands supports.++-}++module Database.MySQL.Protocol.Command where++import           Control.Monad+import           Data.Binary+import           Data.Binary.Get+import           Data.Binary.Parser+import           Data.Binary.Put+import           Data.ByteString                    (ByteString)+import qualified Data.ByteString.Lazy               as L+import           Database.MySQL.Protocol.MySQLValue+import           Database.MySQL.Protocol.Packet++--------------------------------------------------------------------------------+--  Commands++type StmtID = Word32++-- | All support MySQL commands.+--+data Command+    = COM_QUIT                                    -- ^ 0x01+    | COM_INIT_DB        !ByteString              -- ^ 0x02+    | COM_QUERY          !L.ByteString            -- ^ 0x03+    | COM_PING                                    -- ^ 0x0E+    | COM_BINLOG_DUMP    !Word32 !Word16 !Word32 !ByteString -- ^ 0x12+            -- binlog-pos, flags(0x01), server-id, binlog-filename+    | COM_REGISTER_SLAVE !Word32 !ByteString !ByteString !ByteString !Word16 !Word32 !Word32 -- ^ 0x15+            -- server-id, slaves hostname, slaves user, slaves password,  slaves port, replication rank(ignored), master-id(usually 0)+    | COM_STMT_PREPARE   !L.ByteString            -- ^ 0x16 statement+    | COM_STMT_EXECUTE   !StmtID ![MySQLValue] !BitMap -- ^ 0x17 stmtId, params+    | COM_STMT_CLOSE     !StmtID                  -- ^ 0x19 stmtId+    | COM_STMT_RESET     !StmtID                  -- ^ 0x1A stmtId+    | COM_UNSUPPORTED+   deriving (Show, Eq)++putCommand :: Command -> Put+putCommand COM_QUIT              = putWord8 0x01+putCommand (COM_INIT_DB db)      = putWord8 0x02 >> putByteString db+putCommand (COM_QUERY q)         = putWord8 0x03 >> putLazyByteString q+putCommand COM_PING              = putWord8 0x0E+putCommand (COM_BINLOG_DUMP pos flags sid fname) = do+    putWord8 0x12+    putWord32le pos+    putWord16le flags+    putWord32le sid+    putByteString fname+putCommand (COM_REGISTER_SLAVE sid shost susr spass sport rrank mid) = do+    putWord8 0x15+    putWord32le sid+    putLenEncBytes shost+    putLenEncBytes susr+    putLenEncBytes spass+    putWord16le sport+    putWord32le rrank+    putWord32le mid+putCommand (COM_STMT_PREPARE stmt) = putWord8 0x16 >> putLazyByteString stmt+putCommand (COM_STMT_EXECUTE stid params nullmap) = do+    putWord8 0x17+    putWord32le stid+    putWord8 0x00 -- we only use @CURSOR_TYPE_NO_CURSOR@ here+    putWord32le 1 -- const 1+    unless (null params) $ do+        putByteString (fromBitMap nullmap)+        putWord8 0x01    -- always use new-params-bound-flag+        mapM_ putParamMySQLType params+        forM_ params putBinaryField++putCommand (COM_STMT_CLOSE stid) = putWord8 0x19 >> putWord32le stid+putCommand (COM_STMT_RESET stid) = putWord8 0x1A >> putWord32le stid+putCommand _                     = error "unsupported command"++--------------------------------------------------------------------------------+--  Prepared statment related++-- | call 'isOK' with this packet return true+data StmtPrepareOK = StmtPrepareOK+    { stmtId        :: !StmtID+    , stmtColumnCnt :: !Int+    , stmtParamCnt  :: !Int+    , stmtWarnCnt   :: !Int+    } deriving (Show, Eq)++getStmtPrepareOK :: Get StmtPrepareOK+getStmtPrepareOK = do+    skipN 1 -- OK byte+    stmtid <- getWord32le+    cc <- fromIntegral <$> getWord16le+    pc <- fromIntegral <$> getWord16le+    skipN 1 -- reserved+    wc <- fromIntegral <$> getWord16le+    return (StmtPrepareOK stmtid cc pc wc)+{-# INLINE getStmtPrepareOK #-}
+ src/Database/MySQL/Protocol/Escape.hs view
@@ -0,0 +1,146 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}++{-|+Module      : Database.MySQL.Protocol.Escape+Description : Pure haskell mysql escape+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++This module provide escape machinery for bytes and text types.++reference: <http://dev.mysql.com/doc/refman/5.7/en/string-literals.html>++    * Escape Sequence	Character Represented by Sequence+    * \0              	An ASCII NUL (X'00') character+    * \'              	A single quote (“'”) character+    * \"              	A double quote (“"”) character+    * \b              	A backspace character+    * \n              	A newline (linefeed) character+    * \r              	A carriage return character+    * \t              	A tab character+    * \Z              	ASCII 26 (Control+Z); see note following the table+    * \\              	A backslash (“\”) character+    * \%              	A “%” character; see note following the table+    * \_              	A “_” character; see note following the table++The @\%@ and @\_@ sequences are used to search for literal instances of @%@ and @_@ in pattern-matching contexts where they would otherwise be interpreted as wildcard characters, so we won't auto escape @%@ or @_@ here.++-}++module Database.MySQL.Protocol.Escape where++import           Control.Monad            (forM_)+import           Data.ByteString          (ByteString)+import qualified Data.ByteString.Internal as B+import           Data.Text                (Text)+import qualified Data.Text.Array          as TA+import qualified Data.Text.Internal       as T+import           Data.Word+import           Foreign.ForeignPtr       (withForeignPtr)+import           Foreign.Ptr              (Ptr, minusPtr, plusPtr)+import           Foreign.Storable         (peek, poke, pokeByteOff)+import           GHC.IO                   (unsafeDupablePerformIO)++escapeText :: Text -> Text+#if MIN_VERSION_text(2,0,0)+escapeText (T.Text arr off len)+    | len <= 0  = T.empty+    | otherwise =+        let (arr', len') =  TA.run2 $ do+                marr <- TA.new (len * 2)+                loop arr (off + len) marr off 0+        in T.Text arr' 0 len'+  where+    escape c marr ix = do+        TA.unsafeWrite marr ix 92+        TA.unsafeWrite marr (ix+1) c++    loop oarr oend marr !ix !ix'+        | ix == oend = return (marr, ix')+        | otherwise  = do+            let c = TA.unsafeIndex oarr ix+                cs = c : [ TA.unsafeIndex oarr (ix+1) | c >= 0xC0 ]+                      ++ [ TA.unsafeIndex oarr (ix+2) | c >= 0xE0 ]+                      ++ [ TA.unsafeIndex oarr (ix+3) | c >= 0xF0 ]+                go2 = loop oarr oend marr (ix+1) (ix'+2)+                goN = do+                  forM_ (zip [0..4] cs) $ \(di,c') -> TA.unsafeWrite marr (ix' + di) c'+                  loop oarr oend marr (ix + length cs) (ix' + length cs)+            if  | c == 0+                    || c == 39+                    || c == 34 -> escape c   marr ix' >> go2 -- \0 \' \"+                | c == 8       -> escape 98  marr ix' >> go2 -- \b+                | c == 10      -> escape 110 marr ix' >> go2 -- \n+                | c == 13      -> escape 114 marr ix' >> go2 -- \r+                | c == 9       -> escape 116 marr ix' >> go2 -- \t+                | c == 26      -> escape 90  marr ix' >> go2 -- \Z+                | c == 92      -> escape 92  marr ix' >> go2 -- \\++                | otherwise    -> goN+#else+escapeText (T.Text arr off len)+    | len <= 0  = T.empty+    | otherwise =+        let (arr', len') =  TA.run2 $ do+                marr <- TA.new (len * 2)+                loop arr (off + len) marr off 0+        in T.Text arr' 0 len'+  where+    escape c marr ix = do+        TA.unsafeWrite marr ix 92+        TA.unsafeWrite marr (ix+1) c++    loop oarr oend marr !ix !ix'+        | ix == oend = return (marr, ix')+        | otherwise  = do+            let c = TA.unsafeIndex oarr ix+                go1 = loop oarr oend marr (ix+1) (ix'+1)+                go2 = loop oarr oend marr (ix+1) (ix'+2)+            if  | c >= 0xD800 && c <= 0xDBFF  -> do let c2 = TA.unsafeIndex oarr (ix+1)+                                                    TA.unsafeWrite marr ix' c+                                                    TA.unsafeWrite marr (ix'+1) c2+                                                    loop oarr oend marr (ix+2) (ix'+2)+                | c == 0+                    || c == 39+                    || c == 34 -> escape c   marr ix' >> go2 -- \0 \' \"+                | c == 8       -> escape 98  marr ix' >> go2 -- \b+                | c == 10      -> escape 110 marr ix' >> go2 -- \n+                | c == 13      -> escape 114 marr ix' >> go2 -- \r+                | c == 9       -> escape 116 marr ix' >> go2 -- \t+                | c == 26      -> escape 90  marr ix' >> go2 -- \Z+                | c == 92      -> escape 92  marr ix' >> go2 -- \\++                | otherwise    -> TA.unsafeWrite marr ix' c >> go1+#endif++escapeBytes :: ByteString -> ByteString+escapeBytes (B.PS fp s len) = unsafeDupablePerformIO $ withForeignPtr fp $ \ a ->+    B.createUptoN (len * 2) $ \ b -> do+        b' <- loop (a `plusPtr` s) (a `plusPtr` s `plusPtr` len) b+        return (b' `minusPtr` b)+  where+    escape :: Word8 -> Ptr Word8 -> IO (Ptr Word8)+    escape c p = do+        poke p 92+        pokeByteOff p 1 c+        return (p `plusPtr` 2)++    loop !a aend !b+        | a == aend = return b+        | otherwise = do+            c <- peek a+            if  | c == 0+                    || c == 39+                    || c == 34 -> escape c   b >>= loop (a `plusPtr` 1) aend -- \0 \' \"+                | c == 8       -> escape 98  b >>= loop (a `plusPtr` 1) aend -- \b+                | c == 10      -> escape 110 b >>= loop (a `plusPtr` 1) aend -- \n+                | c == 13      -> escape 114 b >>= loop (a `plusPtr` 1) aend -- \r+                | c == 9       -> escape 116 b >>= loop (a `plusPtr` 1) aend -- \t+                | c == 26      -> escape 90  b >>= loop (a `plusPtr` 1) aend -- \Z+                | c == 92      -> escape 92  b >>= loop (a `plusPtr` 1) aend -- \\++                | otherwise    -> poke b c >> loop (a `plusPtr` 1) aend (b `plusPtr` 1)
+ src/Database/MySQL/Protocol/MySQLValue.hs view
@@ -0,0 +1,569 @@+{-# OPTIONS_GHC -funbox-strict-fields #-}++{-|+Module      : Database.MySQL.Protocol.MySQLValue+Description : Text and binary protocol+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++Core text and binary row decoder/encoder machinery.++-}++module Database.MySQL.Protocol.MySQLValue+  ( -- * MySQLValue decoder and encoder+    MySQLValue(..)+  , putParamMySQLType+  , getTextField+  , putTextField+  , getTextRow+  , getTextRowVector+  , getBinaryField+  , putBinaryField+  , getBinaryRow+  , getBinaryRowVector+  -- * Internal utilities+  , getBits+  , BitMap(..)+  , isColumnSet+  , isColumnNull+  , makeNullMap+  ) where++import qualified Blaze.Text                         as Textual+import           Control.Monad+import           Data.Binary.Put+import           Data.Binary.Parser+import           Data.Bits+import           Data.ByteString                    (ByteString)+import qualified Data.ByteString                    as B+import qualified Data.ByteString.Builder            as BB+import           Data.ByteString.Builder.Scientific (FPFormat (..),+                                                     formatScientificBuilder)+import qualified Data.ByteString.Char8              as BC+import qualified Data.ByteString.Lazy               as L+import qualified Data.ByteString.Lex.Fractional     as LexFrac+import qualified Data.ByteString.Lex.Integral       as LexInt+import qualified Data.ByteString.Unsafe             as B+import           Data.Fixed                         (Pico)+import           Data.Int+import           Data.Scientific                    (Scientific)+import           Data.Text                          (Text)+import qualified Data.Text.Encoding                 as T+import           Data.Time.Calendar                 (Day, fromGregorian,+                                                     toGregorian)+import           Data.Time.Format                   (defaultTimeLocale,+                                                     formatTime)+import           Data.Time.LocalTime                (LocalTime (..),+                                                     TimeOfDay (..))+import           Data.Word+import           Database.MySQL.Protocol.ColumnDef+import           Database.MySQL.Protocol.Escape+import           Database.MySQL.Protocol.Packet+import           GHC.Generics                       (Generic)+import qualified Data.Vector                        as V++--------------------------------------------------------------------------------+-- | Data type mapping between MySQL values and haskell values.+--+-- There're some subtle differences between MySQL values and haskell values:+--+-- MySQL's @DATETIME@ and @TIMESTAMP@ are different on timezone handling:+--+--  * DATETIME and DATE is just a represent of a calendar date, it has no timezone information involved,+--  you always get the same value as you put no matter what timezone you're using with MySQL.+--+--  * MySQL converts TIMESTAMP values from the current time zone to UTC for storage,+--  and back from UTC to the current time zone for retrieval. If you put a TIMESTAMP with timezone A,+--  then read it with timezone B, you may get different result because of this conversion, so always+--  be careful about setting up the right timezone with MySQL, you can do it with a simple @SET time_zone = timezone;@+--  for more info on timezone support, please read <http://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html>+--+--  So we use 'LocalTime' to present both @DATETIME@ and @TIMESTAMP@, but the local here is different.+--+-- MySQL's @TIME@ type can present time of day, but also elapsed time or a time interval between two events.+-- @TIME@ values may range from @-838:59:59@ to @838:59:59@, so 'MySQLTime' values consist of a sign and a+-- 'TimeOfDay' whose hour part may exceeded 24. you can use @timeOfDayToTime@ to get the absolute time interval.+--+-- Under MySQL >= 5.7, @DATETIME@, @TIMESTAMP@ and @TIME@ may contain fractional part, which matches haskell's+-- precision.+--+data MySQLValue+    = MySQLDecimal       !Scientific   -- ^ DECIMAL, NEWDECIMAL+    | MySQLInt8U         !Word8        -- ^ Unsigned TINY+    | MySQLInt8          !Int8         -- ^ TINY+    | MySQLInt16U        !Word16       -- ^ Unsigned SHORT+    | MySQLInt16         !Int16        -- ^ SHORT+    | MySQLInt32U        !Word32       -- ^ Unsigned LONG, INT24+    | MySQLInt32         !Int32        -- ^ LONG, INT24+    | MySQLInt64U        !Word64       -- ^ Unsigned LONGLONG+    | MySQLInt64         !Int64        -- ^ LONGLONG+    | MySQLFloat         !Float        -- ^ IEEE 754 single precision format+    | MySQLDouble        !Double       -- ^ IEEE 754 double precision format+    | MySQLYear          !Word16       -- ^ YEAR+    | MySQLDateTime      !LocalTime    -- ^ DATETIME+    | MySQLTimeStamp     !LocalTime    -- ^ TIMESTAMP+    | MySQLDate          !Day              -- ^ DATE+    | MySQLTime          !Word8 !TimeOfDay -- ^ sign(0 = non-negative, 1 = negative) hh mm ss microsecond+                                           -- The sign is OPPOSITE to binlog one !!!+    | MySQLGeometry      !ByteString       -- ^ todo: parsing to something meanful+    | MySQLBytes         !ByteString+    | MySQLBit           !Word64+    | MySQLText          !Text+    | MySQLNull+  deriving (Show, Eq, Generic)++-- | Put 'FieldType' and usigned bit(0x80/0x00) for 'MySQLValue's.+--+putParamMySQLType :: MySQLValue -> Put+putParamMySQLType (MySQLDecimal      _)  = putFieldType mySQLTypeDecimal  >> putWord8 0x00+putParamMySQLType (MySQLInt8U        _)  = putFieldType mySQLTypeTiny     >> putWord8 0x80+putParamMySQLType (MySQLInt8         _)  = putFieldType mySQLTypeTiny     >> putWord8 0x00+putParamMySQLType (MySQLInt16U       _)  = putFieldType mySQLTypeShort    >> putWord8 0x80+putParamMySQLType (MySQLInt16        _)  = putFieldType mySQLTypeShort    >> putWord8 0x00+putParamMySQLType (MySQLInt32U       _)  = putFieldType mySQLTypeLong     >> putWord8 0x80+putParamMySQLType (MySQLInt32        _)  = putFieldType mySQLTypeLong     >> putWord8 0x00+putParamMySQLType (MySQLInt64U       _)  = putFieldType mySQLTypeLongLong >> putWord8 0x80+putParamMySQLType (MySQLInt64        _)  = putFieldType mySQLTypeLongLong >> putWord8 0x00+putParamMySQLType (MySQLFloat        _)  = putFieldType mySQLTypeFloat    >> putWord8 0x00+putParamMySQLType (MySQLDouble       _)  = putFieldType mySQLTypeDouble   >> putWord8 0x00+putParamMySQLType (MySQLYear         _)  = putFieldType mySQLTypeShort    >> putWord8 0x80+putParamMySQLType (MySQLDateTime     _)  = putFieldType mySQLTypeDateTime >> putWord8 0x00+putParamMySQLType (MySQLTimeStamp    _)  = putFieldType mySQLTypeTimestamp>> putWord8 0x00+putParamMySQLType (MySQLDate         _)  = putFieldType mySQLTypeDate     >> putWord8 0x00+putParamMySQLType (MySQLTime       _ _)  = putFieldType mySQLTypeTime     >> putWord8 0x00+putParamMySQLType (MySQLBytes        _)  = putFieldType mySQLTypeBlob     >> putWord8 0x00+putParamMySQLType (MySQLGeometry     _)  = putFieldType mySQLTypeGeometry >> putWord8 0x00+putParamMySQLType (MySQLBit          _)  = putFieldType mySQLTypeLongLong >> putWord8 0x80+putParamMySQLType (MySQLText         _)  = putFieldType mySQLTypeString   >> putWord8 0x00+putParamMySQLType MySQLNull              = putFieldType mySQLTypeNull     >> putWord8 0x00++--------------------------------------------------------------------------------+-- | Text protocol decoder+getTextField :: ColumnDef -> Get MySQLValue+getTextField f+    | t == mySQLTypeNull            = pure MySQLNull+    | t == mySQLTypeDecimal+        || t == mySQLTypeNewDecimal = feedLenEncBytes t MySQLDecimal fracLexer+    | t == mySQLTypeTiny            = if isUnsigned then feedLenEncBytes t MySQLInt8U intLexer+                                                    else feedLenEncBytes t MySQLInt8 intLexer+    | t == mySQLTypeShort           = if isUnsigned then feedLenEncBytes t MySQLInt16U intLexer+                                                    else feedLenEncBytes t MySQLInt16 intLexer+    | t == mySQLTypeLong+        || t == mySQLTypeInt24      = if isUnsigned then feedLenEncBytes t MySQLInt32U intLexer+                                                    else feedLenEncBytes t MySQLInt32 intLexer+    | t == mySQLTypeLongLong        = if isUnsigned then feedLenEncBytes t MySQLInt64U intLexer+                                                    else feedLenEncBytes t MySQLInt64 intLexer+    | t == mySQLTypeFloat           = feedLenEncBytes t MySQLFloat fracLexer+    | t == mySQLTypeDouble          = feedLenEncBytes t MySQLDouble fracLexer+    | t == mySQLTypeYear            = feedLenEncBytes t MySQLYear intLexer+    | t == mySQLTypeTimestamp+        || t == mySQLTypeTimestamp2 = feedLenEncBytes t MySQLTimeStamp $ \ bs ->+                                          guard (B.length bs >= 12) >>+                                          LocalTime <$> dateParser bs <*> timeParser (B.drop 11 bs)+    | t == mySQLTypeDateTime+        || t == mySQLTypeDateTime2  = feedLenEncBytes t MySQLDateTime $ \ bs ->+                                          guard (B.length bs >= 12) >>+                                          LocalTime <$> dateParser bs <*> timeParser (B.drop 11 bs)+    | t == mySQLTypeDate+        || t == mySQLTypeNewDate    = feedLenEncBytes t MySQLDate dateParser+    | t == mySQLTypeTime+        || t == mySQLTypeTime2      = feedLenEncBytes t id $ \ bs ->+                                          guard (not (B.null bs)) >>+                                          if B.index bs 0 == 45  -- '-'+                                               then MySQLTime 1 <$> timeParser (B.drop 1 bs)+                                               else MySQLTime 0 <$> timeParser bs++    | t == mySQLTypeGeometry        = MySQLGeometry <$> getLenEncBytes+    | t == mySQLTypeVarChar+        || t == mySQLTypeEnum+        || t == mySQLTypeSet+        || t == mySQLTypeTinyBlob+        || t == mySQLTypeMediumBlob+        || t == mySQLTypeLongBlob+        || t == mySQLTypeBlob+        || t == mySQLTypeVarString+        || t == mySQLTypeString     = (if isText then MySQLText . T.decodeUtf8 else MySQLBytes) <$> getLenEncBytes++    | t == mySQLTypeBit             = MySQLBit <$> (getBits =<< getLenEncInt)++    | otherwise                     = fail $ "Database.MySQL.Protocol.MySQLValue: missing text decoder for " ++ show t+  where+    t = columnType f+    isUnsigned = flagUnsigned (columnFlags f)+    isText = columnCharSet f /= 63+    intLexer bs = fst <$> LexInt.readSigned LexInt.readDecimal bs+    fracLexer bs = fst <$> LexFrac.readSigned LexFrac.readDecimal bs+    dateParser bs = do+        (yyyy, rest) <- LexInt.readDecimal bs+        guard (not (B.null rest))+        (mm, rest') <- LexInt.readDecimal (B.tail rest)+        guard (not (B.null rest'))+        (dd, _) <- LexInt.readDecimal (B.tail rest')+        return (fromGregorian yyyy mm dd)++    timeParser bs = do+        (hh, rest) <- LexInt.readDecimal bs+        guard (not (B.null rest))+        (mm, rest') <- LexInt.readDecimal (B.tail rest)+        guard (not (B.null rest'))+        (ss, _) <- LexFrac.readDecimal (B.tail rest')+        return (TimeOfDay hh mm ss)+++feedLenEncBytes :: FieldType -> (t -> b) -> (ByteString -> Maybe t) -> Get b+feedLenEncBytes typ con parser = do+    bs <- getLenEncBytes+    case parser bs of+        Just v -> return (con v)+        Nothing -> fail $ "Database.MySQL.Protocol.MySQLValue: parsing " ++ show typ ++ " failed, \+                          \input: " ++ BC.unpack bs+{-# INLINE feedLenEncBytes #-}++--------------------------------------------------------------------------------+-- | Text protocol encoder+putTextField :: MySQLValue -> Put+putTextField (MySQLDecimal    n) = putBuilder (formatScientificBuilder Fixed Nothing n)+putTextField (MySQLInt8U      n) = putBuilder (Textual.integral n)+putTextField (MySQLInt8       n) = putBuilder (Textual.integral n)+putTextField (MySQLInt16U     n) = putBuilder (Textual.integral n)+putTextField (MySQLInt16      n) = putBuilder (Textual.integral n)+putTextField (MySQLInt32U     n) = putBuilder (Textual.integral n)+putTextField (MySQLInt32      n) = putBuilder (Textual.integral n)+putTextField (MySQLInt64U     n) = putBuilder (Textual.integral n)+putTextField (MySQLInt64      n) = putBuilder (Textual.integral n)+putTextField (MySQLFloat      x) = putBuilder (Textual.float x)+putTextField (MySQLDouble     x) = putBuilder (Textual.double x)+putTextField (MySQLYear       n) = putBuilder (Textual.integral n)+putTextField (MySQLDateTime  dt) = putInQuotes $+                                      putByteString (BC.pack (formatTime defaultTimeLocale "%F %T%Q" dt))+putTextField (MySQLTimeStamp dt) = putInQuotes $+                                      putByteString (BC.pack (formatTime defaultTimeLocale "%F %T%Q" dt))+putTextField (MySQLDate       d) = putInQuotes $+                                      putByteString (BC.pack (formatTime defaultTimeLocale "%F" d))+putTextField (MySQLTime  sign t) = putInQuotes $ do+                                      when (sign == 1) (putCharUtf8 '-')+                                      putByteString (BC.pack (formatTime defaultTimeLocale "%T%Q" t))+                                      -- this works even for hour > 24+putTextField (MySQLGeometry  bs) = putInQuotes $ putByteString . escapeBytes $ bs+putTextField (MySQLBytes     bs) = putInQuotes $ putByteString . escapeBytes $ bs+putTextField (MySQLText       t) = putInQuotes $+                                      putByteString . T.encodeUtf8 . escapeText $ t+putTextField (MySQLBit        b) = do putBuilder "b\'"+                                      putBuilder . execPut $ putTextBits b+                                      putCharUtf8 '\''+  where+    putTextBits :: Word64 -> Put+    putTextBits word = forM_ [63,62..0] $ \ pos ->+            if word `testBit` pos then putCharUtf8 '1' else putCharUtf8 '0'+    {-# INLINE putTextBits #-}++putTextField MySQLNull           = putBuilder "NULL"++putInQuotes :: Put -> Put+putInQuotes p = putCharUtf8 '\'' >> p >> putCharUtf8 '\''+{-# INLINE putInQuotes #-}++--------------------------------------------------------------------------------+-- | Text row decoder+getTextRow :: [ColumnDef] -> Get [MySQLValue]+getTextRow fs = forM fs $ \ f -> do+    p <- peek+    if p == 0xFB+    then skipN 1 >> return MySQLNull+    else getTextField f+{-# INLINE getTextRow #-}++getTextRowVector :: V.Vector ColumnDef -> Get (V.Vector MySQLValue)+getTextRowVector fs = V.forM fs $ \ f -> do+    p <- peek+    if p == 0xFB+    then skipN 1 >> return MySQLNull+    else getTextField f+{-# INLINE getTextRowVector #-}++--------------------------------------------------------------------------------+-- | Binary protocol decoder+getBinaryField :: ColumnDef -> Get MySQLValue+getBinaryField f+    | t == mySQLTypeNull              = pure MySQLNull+    | t == mySQLTypeDecimal+        || t == mySQLTypeNewDecimal   = feedLenEncBytes t MySQLDecimal fracLexer+    | t == mySQLTypeTiny              = if isUnsigned then MySQLInt8U <$> getWord8+                                                      else MySQLInt8  <$> getInt8+    | t == mySQLTypeShort             = if isUnsigned then MySQLInt16U <$> getWord16le+                                                      else MySQLInt16  <$> getInt16le+    | t == mySQLTypeLong+        || t == mySQLTypeInt24        = if isUnsigned then MySQLInt32U <$> getWord32le+                                                      else MySQLInt32  <$> getInt32le+    | t == mySQLTypeYear              = MySQLYear <$> getWord16le+    | t == mySQLTypeLongLong          = if isUnsigned then MySQLInt64U <$> getWord64le+                                                      else MySQLInt64  <$> getInt64le+    | t == mySQLTypeFloat             = MySQLFloat  <$> getFloatle+    | t == mySQLTypeDouble            = MySQLDouble <$> getDoublele+    | t == mySQLTypeTimestamp+        || t == mySQLTypeTimestamp2   = do+            n <- getLenEncInt+            case n of+               0 -> pure $ MySQLTimeStamp (LocalTime (fromGregorian 0 0 0) (TimeOfDay 0 0 0))+               4 -> do+                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'+                   pure $ MySQLTimeStamp (LocalTime d (TimeOfDay 0 0 0))+               7 -> do+                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'+                   td <- TimeOfDay <$> getInt8' <*> getInt8' <*> getSecond4+                   pure $ MySQLTimeStamp (LocalTime d td)+               11 -> do+                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'+                   td <- TimeOfDay <$> getInt8' <*> getInt8' <*> getSecond8+                   pure $ MySQLTimeStamp (LocalTime d td)+               _ -> fail "Database.MySQL.Protocol.MySQLValue: wrong TIMESTAMP length"+    | t == mySQLTypeDateTime+        || t == mySQLTypeDateTime2    = do+            n <- getLenEncInt+            case n of+               0 -> pure $ MySQLDateTime (LocalTime (fromGregorian 0 0 0) (TimeOfDay 0 0 0))+               4 -> do+                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'+                   pure $ MySQLDateTime (LocalTime d (TimeOfDay 0 0 0))+               7 -> do+                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'+                   td <- TimeOfDay <$> getInt8' <*> getInt8' <*> getSecond4+                   pure $ MySQLDateTime (LocalTime d td)+               11 -> do+                   d <- fromGregorian <$> getYear <*> getInt8' <*> getInt8'+                   td <- TimeOfDay <$> getInt8' <*> getInt8' <*> getSecond8+                   pure $ MySQLDateTime (LocalTime d td)+               _ -> fail "Database.MySQL.Protocol.MySQLValue: wrong DATETIME length"++    | t == mySQLTypeDate+        || t == mySQLTypeNewDate      = do+            n <- getLenEncInt+            case n of+               0 -> pure $ MySQLDate (fromGregorian 0 0 0)+               4 -> MySQLDate <$> (fromGregorian <$> getYear <*> getInt8' <*> getInt8')+               _ -> fail "Database.MySQL.Protocol.MySQLValue: wrong DATE length"++    | t == mySQLTypeTime+        || t == mySQLTypeTime2        = do+            n <- getLenEncInt+            case n of+               0 -> pure $ MySQLTime 0 (TimeOfDay 0 0 0)+               8 -> do+                   sign <- getWord8   -- is_negative(1 if minus, 0 for plus)+                   d <- fromIntegral <$> getWord32le+                   h <-  getInt8'+                   MySQLTime sign <$> (TimeOfDay (d*24 + h) <$> getInt8' <*> getSecond4)++               12 -> do+                   sign <- getWord8   -- is_negative(1 if minus, 0 for plus)+                   d <- fromIntegral <$> getWord32le+                   h <-  getInt8'+                   MySQLTime sign <$> (TimeOfDay (d*24 + h) <$> getInt8' <*> getSecond8)+               _ -> fail "Database.MySQL.Protocol.MySQLValue: wrong TIME length"++    | t == mySQLTypeGeometry          = MySQLGeometry <$> getLenEncBytes+    | t == mySQLTypeVarChar+        || t == mySQLTypeEnum+        || t == mySQLTypeSet+        || t == mySQLTypeTinyBlob+        || t == mySQLTypeMediumBlob+        || t == mySQLTypeLongBlob+        || t == mySQLTypeBlob+        || t == mySQLTypeVarString+        || t == mySQLTypeString       = if isText then MySQLText . T.decodeUtf8 <$> getLenEncBytes+                                                  else MySQLBytes <$> getLenEncBytes+    | t == mySQLTypeBit               = MySQLBit <$> (getBits =<< getLenEncInt)+    | otherwise                       = fail $ "Database.MySQL.Protocol.MySQLValue:\+                                               \ missing binary decoder for " ++ show t+  where+    t = columnType f+    isUnsigned = flagUnsigned (columnFlags f)+    isText = columnCharSet f /= 63+    fracLexer bs = fst <$> LexFrac.readSigned LexFrac.readDecimal bs+    getYear :: Get Integer+    getYear = fromIntegral <$> getWord16le+    getInt8' :: Get Int+    getInt8' = fromIntegral <$> getWord8+    getSecond4 :: Get Pico+    getSecond4 = realToFrac <$> getWord8+    getSecond8 :: Get Pico+    getSecond8 =  do+        s <- getInt8'+        ms <- fromIntegral <$> getWord32le :: Get Int+        pure $! (realToFrac s + realToFrac ms / 1000000 :: Pico)+++-- | Get a bit sequence as a Word64+--+-- Since 'Word64' has a @Bits@ instance, it's easier to deal with in haskell.+--+getBits :: Int -> Get Word64+getBits bytes =+    if  | bytes == 0 || bytes == 1 -> fromIntegral <$> getWord8+        | bytes == 2 -> fromIntegral <$> getWord16be+        | bytes == 3 -> fromIntegral <$> getWord24be+        | bytes == 4 -> fromIntegral <$> getWord32be+        | bytes == 5 -> getWord40be+        | bytes == 6 -> getWord48be+        | bytes == 7 -> getWord56be+        | bytes == 8 -> getWord64be+        | otherwise  -> fail $  "Database.MySQL.Protocol.MySQLValue: \+                                \wrong bit length size: " ++ show bytes+{-# INLINE getBits #-}+++--------------------------------------------------------------------------------+-- | Binary protocol encoder+putBinaryField :: MySQLValue -> Put+putBinaryField (MySQLDecimal    n) = putLenEncBytes . L.toStrict . BB.toLazyByteString $+                                        formatScientificBuilder Fixed Nothing n+putBinaryField (MySQLInt8U      n) = putWord8 n+putBinaryField (MySQLInt8       n) = putWord8 (fromIntegral n)+putBinaryField (MySQLInt16U     n) = putWord16le n+putBinaryField (MySQLInt16      n) = putInt16le n+putBinaryField (MySQLInt32U     n) = putWord32le n+putBinaryField (MySQLInt32      n) = putInt32le n+putBinaryField (MySQLInt64U     n) = putWord64le n+putBinaryField (MySQLInt64      n) = putInt64le n+putBinaryField (MySQLFloat      x) = putFloatle x+putBinaryField (MySQLDouble     x) = putDoublele x+putBinaryField (MySQLYear       n) = putWord16le n+putBinaryField (MySQLTimeStamp (LocalTime date time)) = do putWord8 11    -- always put full+                                                           putBinaryDay date+                                                           putBinaryTime' time+putBinaryField (MySQLDateTime  (LocalTime date time)) = do putWord8 11    -- always put full+                                                           putBinaryDay date+                                                           putBinaryTime' time+putBinaryField (MySQLDate    d)    = do putWord8 4+                                        putBinaryDay d+putBinaryField (MySQLTime sign t)  = do putWord8 12    -- always put full+                                        putWord8 sign+                                        putBinaryTime t+putBinaryField (MySQLGeometry bs)  = putLenEncBytes bs+putBinaryField (MySQLBytes  bs)    = putLenEncBytes bs+putBinaryField (MySQLBit    word)  = putWord64le word+putBinaryField (MySQLText    t)    = putLenEncBytes (T.encodeUtf8 t)+putBinaryField MySQLNull           = return ()++putBinaryDay :: Day -> Put+putBinaryDay d = do let (yyyy, mm, dd) = toGregorian d+                    putWord16le (fromIntegral yyyy)+                    putWord8 (fromIntegral mm)+                    putWord8 (fromIntegral dd)+{-# INLINE putBinaryDay #-}++putBinaryTime' :: TimeOfDay -> Put+putBinaryTime' (TimeOfDay hh mm ss) = do let s = floor ss+                                             ms = floor $ (ss - realToFrac s) * 1000000+                                         putWord8 (fromIntegral hh)+                                         putWord8 (fromIntegral mm)+                                         putWord8 s+                                         putWord32le ms+{-# INLINE putBinaryTime' #-}++putBinaryTime :: TimeOfDay -> Put+putBinaryTime (TimeOfDay hh mm ss) = do let s = floor ss+                                            ms = floor $ (ss - realToFrac s) * 1000000+                                            (d, h) = hh `quotRem` 24  -- hour may exceed 24 here+                                        putWord32le (fromIntegral d)+                                        putWord8 (fromIntegral h)+                                        putWord8 (fromIntegral mm)+                                        putWord8 s+                                        putWord32le ms+{-# INLINE putBinaryTime #-}++--------------------------------------------------------------------------------+-- | Binary row decoder+--+-- MySQL use a special null bitmap without offset = 2 here.+--+getBinaryRow :: [ColumnDef] -> Int -> Get [MySQLValue]+getBinaryRow fields flen = do+    skipN 1           -- 0x00+    let maplen = (flen + 7 + 2) `shiftR` 3+    nullmap <- BitMap <$> getByteString maplen+    go fields nullmap 0+  where+    go :: [ColumnDef] -> BitMap -> Int -> Get [MySQLValue]+    go []     _       _   = pure []+    go (f:fs) nullmap pos = do+        r <- if isColumnNull nullmap pos+                then return MySQLNull+                else getBinaryField f+        let pos' = pos + 1+        rest <- pos' `seq` go fs nullmap pos'+        return (r `seq` (r : rest))+{-# INLINE getBinaryRow #-}++getBinaryRowVector :: V.Vector ColumnDef -> Int -> Get (V.Vector MySQLValue)+getBinaryRowVector fields flen = do+    skipN 1           -- 0x00+    let maplen = (flen + 7 + 2) `shiftR` 3+    nullmap <- BitMap <$> getByteString maplen+    (`V.imapM` fields) $ \ pos f ->+        if isColumnNull nullmap pos then return MySQLNull else getBinaryField f+{-# INLINE getBinaryRowVector #-}++--------------------------------------------------------------------------------+-- | Use 'ByteString' to present a bitmap.+--+-- When used for represent bits values, the underlining 'ByteString' follows:+--+--  * byteString: head       -> tail+--  * bit:        high bit   -> low bit+--+-- When used as a null-map/present-map, every bit inside a byte+-- is mapped to a column, the mapping order is following:+--+--  * byteString: head -> tail+--  * column:     left -> right+--+-- We don't use 'Int64' here because there maybe more than 64 columns.+--+newtype BitMap = BitMap { fromBitMap :: ByteString } deriving (Eq, Show)++-- | Test if a column is set(binlog protocol).+--+-- The number counts from left to right.+--+isColumnSet :: BitMap -> Int -> Bool+isColumnSet (BitMap bitmap) pos =+  let i = pos `unsafeShiftR` 3+      j = pos .&. 7+  in (bitmap `B.unsafeIndex` i) `testBit` j+{-# INLINE isColumnSet #-}++-- | Test if a column is null(binary protocol).+--+-- The number counts from left to right.+--+isColumnNull :: BitMap -> Int -> Bool+isColumnNull (BitMap nullmap) pos =+  let+    pos' = pos + 2+    i    = pos' `unsafeShiftR` 3+    j    = pos' .&. 7+  in (nullmap `B.unsafeIndex` i) `testBit` j+{-# INLINE isColumnNull #-}++-- | Make a nullmap for params(binary protocol) without offset.+--+makeNullMap :: [MySQLValue] -> BitMap+makeNullMap values = BitMap . B.pack $ go values 0x00 0+  where+    go :: [MySQLValue] -> Word8 -> Int -> [Word8]+    go []             byte   8  = [byte]+    go vs             byte   8  = byte : go vs 0x00 0+    go []             byte   _  = [byte]+    go (MySQLNull:vs) byte pos  = let pos' = pos + 1+                                      byte' = byte .|. bit pos+                                  in pos' `seq` byte' `seq` go vs byte' pos'+    go (_        :vs) byte pos  = let pos' = pos + 1 in pos' `seq` go vs byte pos'++--------------------------------------------------------------------------------+-- TODO: add helpers to parse mySQLTypeGEOMETRY+-- reference: https://github.com/felixge/node-mysql/blob/master/lib/protocol/Parser.js
+ src/Database/MySQL/Protocol/Packet.hs view
@@ -0,0 +1,311 @@+{-# OPTIONS_GHC -funbox-strict-fields #-}++{-|+Module      : Database.MySQL.Protocol.Packet+Description : MySQL packet type and various helpers.+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++MySQL packet decoder&encoder, and varities utility.++-}++module Database.MySQL.Protocol.Packet where++import           Control.Exception     (Exception (..), throwIO)+import           Data.Binary.Parser+import           Data.Binary.Put+import           Data.Binary           (Binary(..), encode)+import           Data.Bits+import qualified Data.ByteString       as B+import           Data.ByteString.Char8 as BC+import qualified Data.ByteString.Lazy  as L+import           Data.Int.Int24+import           Data.Int+import           Data.Word+import           Data.Typeable+import           Data.Word.Word24++--------------------------------------------------------------------------------+-- | MySQL packet type+--+data Packet = Packet+    { pLen  :: !Int64+    , pSeqN :: !Word8+    , pBody :: !L.ByteString+    } deriving (Show, Eq)++putPacket :: Packet -> Put+putPacket (Packet len seqN body)  = do+    putWord24le (fromIntegral len)+    putWord8 seqN+    putLazyByteString body+{-# INLINE putPacket #-}++getPacket :: Get Packet+getPacket = do+    len <- fromIntegral <$> getWord24le+    seqN <- getWord8+    body <- getLazyByteString len+    return (Packet len seqN body)+{-# INLINE getPacket #-}++instance Binary Packet where+    put = putPacket+    {-# INLINE put #-}+    get = getPacket+    {-# INLINE get #-}++isERR :: Packet -> Bool+isERR p = L.index (pBody p) 0 == 0xFF+{-# INLINE isERR #-}++isOK :: Packet -> Bool+isOK p  = L.index (pBody p) 0 == 0x00+{-# INLINE isOK #-}++isEOF :: Packet -> Bool+isEOF p = L.index (pBody p) 0 == 0xFE+{-# INLINE isEOF #-}++-- | Is this an AuthMoreData packet? (first byte 0x01)+-- Used during authentication handshake for caching_sha2_password.+isAuthMoreData :: Packet -> Bool+isAuthMoreData p = L.index (pBody p) 0 == 0x01+{-# INLINE isAuthMoreData #-}++-- | Is this an AuthSwitchRequest packet? (first byte 0xFE)+-- Same marker as EOF but used in authentication context.+isAuthSwitch :: Packet -> Bool+isAuthSwitch p = L.index (pBody p) 0 == 0xFE+{-# INLINE isAuthSwitch #-}++-- | Is there more packet to be read?+--+--  https://dev.mysql.com/doc/internals/en/status-flags.html+isThereMore :: OK -> Bool+isThereMore p  = okStatus p .&. 0x08 /= 0+{-# INLINE isThereMore #-}++-- | Decoding packet inside IO, throw 'DecodePacketException' on fail parsing,+-- here we choose stability over correctness by omit incomplete consumed case:+-- if we successful parse a packet, then we don't care if there're bytes left.+--+decodeFromPacket :: Binary a => Packet -> IO a+decodeFromPacket = getFromPacket get+{-# INLINE decodeFromPacket #-}++getFromPacket :: Get a -> Packet -> IO a+getFromPacket g (Packet _ _ body) = case parseDetailLazy g body of+    Left  (buf, offset, errmsg) -> throwIO (DecodePacketFailed buf offset errmsg)+    Right (_,   _,      r     ) -> return r+{-# INLINE getFromPacket #-}++data DecodePacketException = DecodePacketFailed ByteString ByteOffset String+  deriving (Typeable, Show)+instance Exception DecodePacketException++encodeToPacket :: Binary a => Word8 -> a -> Packet+encodeToPacket seqN payload =+    let s = encode payload+        l = L.length s+    in Packet l seqN s+{-# INLINE encodeToPacket #-}++putToPacket :: Word8 -> Put -> Packet+putToPacket seqN payload =+    let s = runPut payload+        l = L.length s+    in Packet l seqN s+{-# INLINE putToPacket #-}++--------------------------------------------------------------------------------+-- OK, ERR, EOF++-- | You may get interested in 'OK' packet because it provides information about+-- successful operations.+--+data OK = OK+    { okAffectedRows :: !Int      -- ^ affected row number+    , okLastInsertID :: !Int      -- ^ last insert's ID+    , okStatus       :: !Word16+    , okWarningCnt   :: !Word16+    } deriving (Show, Eq)++getOK :: Get OK+getOK = OK <$ skipN 1+           <*> getLenEncInt+           <*> getLenEncInt+           <*> getWord16le+           <*> getWord16le+{-# INLINE getOK #-}++putOK :: OK -> Put+putOK (OK row lid stat wcnt) = do+    putWord8 0x00+    putLenEncInt row+    putLenEncInt lid+    putWord16le stat+    putWord16le wcnt+{-# INLINE putOK #-}++instance Binary OK where+    get = getOK+    {-# INLINE get #-}+    put = putOK+    {-# INLINE put #-}++data ERR = ERR+    { errCode  :: !Word16+    , errState :: !ByteString+    , errMsg   :: !ByteString+    } deriving (Show, Eq)++getERR :: Get ERR+getERR = ERR <$  skipN 1+             <*> getWord16le+             <*  skipN 1+             <*> getByteString 5+             <*> getRemainingByteString+{-# INLINE getERR #-}++putERR :: ERR -> Put+putERR (ERR code stat msg) = do+    putWord8 0xFF+    putWord16le code+    putWord8 35 -- '#'+    putByteString stat+    putByteString msg+{-# INLINE putERR #-}++instance Binary ERR where+    get = getERR+    {-# INLINE get #-}+    put = putERR+    {-# INLINE put #-}++data EOF = EOF+    { eofWarningCnt :: !Word16+    , eofStatus     :: !Word16+    } deriving (Show, Eq)++getEOF :: Get EOF+getEOF = EOF <$  skipN 1+             <*> getWord16le+             <*> getWord16le+{-# INLINE getEOF #-}++putEOF :: EOF -> Put+putEOF (EOF wcnt stat) = do+    putWord8 0xFE+    putWord16le wcnt+    putWord16le stat+{-# INLINE putEOF #-}++instance Binary EOF where+    get = getEOF+    {-# INLINE get #-}+    put = putEOF+    {-# INLINE put #-}++--------------------------------------------------------------------------------+--  Helpers++getByteStringNul :: Get ByteString+getByteStringNul = L.toStrict <$> getLazyByteStringNul+{-# INLINE getByteStringNul #-}++getRemainingByteString :: Get ByteString+getRemainingByteString = L.toStrict <$> getRemainingLazyByteString+{-# INLINE getRemainingByteString #-}++putLenEncBytes :: ByteString -> Put+putLenEncBytes c = do+    putLenEncInt (B.length c)+    putByteString c+{-# INLINE putLenEncBytes #-}++getLenEncBytes :: Get ByteString+getLenEncBytes = getLenEncInt >>= getByteString+{-# INLINE getLenEncBytes #-}++-- | length encoded int+-- https://dev.mysql.com/doc/internals/en/integer.html#packet-Protocol::LengthEncodedInteger+getLenEncInt:: Get Int+getLenEncInt = getWord8 >>= word2Len+  where+    word2Len l+         | l <  0xFB  = pure (fromIntegral l)+         | l == 0xFC  = fromIntegral <$> getWord16le+         | l == 0xFD  = fromIntegral <$> getWord24le+         | l == 0xFE  = fromIntegral <$> getWord64le+         | otherwise = fail $ "invalid length val " ++ show l+{-# INLINE getLenEncInt #-}++putLenEncInt:: Int -> Put+putLenEncInt x+         | x <  251      = putWord8 (fromIntegral x)+         | x < 65536     = putWord8 0xFC >> putWord16le (fromIntegral x)+         | x < 16777216  = putWord8 0xFD >> putWord24le (fromIntegral x)+         | otherwise     = putWord8 0xFE >> putWord64le (fromIntegral x)+{-# INLINE putLenEncInt #-}++putWord24le :: Word32 -> Put+putWord24le v = do+    putWord16le $ fromIntegral v+    putWord8 $ fromIntegral (v `shiftR` 16)+{-# INLINE putWord24le #-}++getWord24le :: Get Word32+getWord24le = do+    a <- fromIntegral <$> getWord16le+    b <- fromIntegral <$> getWord8+    return $! a .|. (b `shiftL` 16)+{-# INLINE getWord24le #-}++putWord48le :: Word64 -> Put+putWord48le v = do+    putWord32le $ fromIntegral v+    putWord16le $ fromIntegral (v `shiftR` 32)+{-# INLINE putWord48le #-}++getWord48le :: Get Word64+getWord48le = do+    a <- fromIntegral <$> getWord32le+    b <- fromIntegral <$> getWord16le+    return $! a .|. (b `shiftL` 32)+{-# INLINE getWord48le #-}++getWord24be :: Get Word24+getWord24be = do+    a <- fromIntegral <$> getWord16be+    b <- fromIntegral <$> getWord8+    return $! b .|. (a `shiftL` 8)+{-# INLINE getWord24be #-}++getInt24be :: Get Int24+getInt24be = do+    a <- fromIntegral <$> getWord16be+    b <- fromIntegral <$> getWord8+    return $! fromIntegral $ (b .|. (a `shiftL` 8) :: Word24)+{-# INLINE getInt24be #-}++getWord40be, getWord48be, getWord56be :: Get Word64+getWord40be = do+    a <- fromIntegral <$> getWord32be+    b <- fromIntegral <$> getWord8+    return $! (a `shiftL` 8) .|. b+getWord48be = do+    a <- fromIntegral <$> getWord32be+    b <- fromIntegral <$> getWord16be+    return $! (a `shiftL` 16) .|. b+getWord56be = do+    a <- fromIntegral <$> getWord32be+    b <- fromIntegral <$> getWord24be+    return $! (a `shiftL` 24) .|. b+{-# INLINE getWord40be #-}+{-# INLINE getWord48be #-}+{-# INLINE getWord56be #-}
+ src/Database/MySQL/Query.hs view
@@ -0,0 +1,80 @@+module Database.MySQL.Query where++import           Data.String               (IsString (..))+import           Control.Exception         (throw, Exception)+import           Data.Typeable+import qualified Data.ByteString.Lazy      as L+import qualified Data.ByteString.Lazy.Char8     as LC+import qualified Data.ByteString.Builder   as BB+import           Control.Arrow             (first)+import           Database.MySQL.Protocol.MySQLValue+import           Data.Binary.Put++-- | Query string type borrowed from @mysql-simple@.+--+-- This type is intended to make it difficult to+-- construct a SQL query by concatenating string fragments, as that is+-- an extremely common way to accidentally introduce SQL injection+-- vulnerabilities into an application.+--+-- This type is an instance of 'IsString', so the easiest way to+-- construct a query is to enable the @OverloadedStrings@ language+-- extension and then simply write the query in double quotes.+--+-- The underlying type is a 'L.ByteString', and literal Haskell strings+-- that contain Unicode characters will be correctly transformed to+-- UTF-8.+--+newtype Query = Query { fromQuery :: L.ByteString } deriving (Eq, Ord, Typeable)++instance Show Query where+    show = show . fromQuery++instance Read Query where+    readsPrec i = fmap (first Query) . readsPrec i++instance IsString Query where+    fromString = Query . BB.toLazyByteString . BB.stringUtf8++-- | A type to wrap a query parameter in to allow for single and multi-valued parameters.+--+-- The behavior of 'Param' can be illustrated by following example:+--+-- @+--    render $ One (MySQLText "hello") = hello+--    render $ Many [MySQLText "hello", MySQLText "world"] = hello, world+--    render $ Many [] = null+-- @+--+-- So you can now write a query like this: @ SELECT * FROM test WHERE _id IN (?, 888) @+-- and use 'Many' 'Param' to fill the hole. There's no equivalent for prepared statement sadly.+--+data Param = One  MySQLValue+           | Many [MySQLValue]++-- | A type that may be used as a single parameter to a SQL query. Inspired from @mysql-simple@.+class QueryParam a where+    render :: a -> Put+    -- ^ Prepare a value for substitution into a query string.++instance QueryParam Param where+    render (One x)      = putTextField x+    render (Many [])    = putTextField MySQLNull+    render (Many (x:[]))= putTextField x+    render (Many (x:xs))= do putTextField x+                             mapM_ (\f -> putCharUtf8 ',' >> putTextField f) xs++instance QueryParam MySQLValue where+    render = putTextField++renderParams :: QueryParam p => Query -> [p] -> Query+renderParams (Query qry) params =+    let fragments = LC.split '?' qry+    in Query . runPut $ merge fragments params+  where+    merge [x]    []     = putLazyByteString x+    merge (x:xs) (y:ys) = putLazyByteString x >> render y >> merge xs ys+    merge _     _       = throw WrongParamsCount++data WrongParamsCount = WrongParamsCount deriving (Show, Typeable)+instance Exception WrongParamsCount
+ src/Database/MySQL/TLS.hs view
@@ -0,0 +1,98 @@+{-|+Module      : Database.MySQL.Connection+Description : TLS support for mysql-haskell via @tls@ package.+Copyright   : (c) Winterland, 2016+License     : BSD+Maintainer  : drkoster@qq.com+Stability   : experimental+Portability : PORTABLE++This module provides secure MySQL connection using 'tls' package, please make sure your certificate is v3 extension enabled.++-}++module Database.MySQL.TLS (+      connect+    , connectDetail+    , module Data.TLSSetting+    ) where++import           Control.Exception              (bracketOnError, throwIO, catch, SomeException)+import           Control.Monad                  (void)+import qualified Data.Binary                    as Binary+import qualified Data.Binary.Put                as Binary+import           Data.ByteString                (ByteString)+import qualified Data.ByteString                as B+import qualified Data.ByteString.Lazy           as L+import           Data.Word                      (Word8)+import qualified Data.Connection                as Conn+import           Data.IORef                     (newIORef)+import           Data.TLSSetting+import           Database.MySQL.Connection      hiding (connect, connectDetail)+import           Database.MySQL.Protocol.Auth+import           Database.MySQL.Protocol.Command+import           Database.MySQL.Protocol.Packet+import           System.IO.Streams               (InputStream)+import qualified Network.TLS                    as TLS+import qualified System.IO.Streams.TCP          as TCP+import qualified Data.Connection                as TCP+import qualified System.IO.Streams.TLS          as TLS++--------------------------------------------------------------------------------++-- | Provide a 'TLS.ClientParams' and a subject name to establish a TLS connection.+--+connect :: ConnectInfo -> (TLS.ClientParams, String) -> IO MySQLConn+connect c cp = fmap snd (connectDetail c cp)++connectDetail :: ConnectInfo -> (TLS.ClientParams, String) -> IO (Greeting, MySQLConn)+connectDetail (ConnectInfo host port db user pass charset) (cparams, subName) =+    bracketOnError (connectWithBufferSize host port bUFSIZE)+       (TCP.close) $ \ c -> do+            let is = TCP.source c+            is' <- decodeInputStream is+            p <- readPacket is'+            greet <- decodeFromPacket p+            if supportTLS (greetingCaps greet)+            then do+                let cparams' = cparams {+                            TLS.clientUseServerNameIndication = False+                        ,   TLS.clientServerIdentification = (subName, "")+                        }+                let (sock, sockAddr) = Conn.connExtraInfo c+                write c (encodeToPacket 1 $ sslRequest charset)+                bracketOnError (TLS.contextNew sock cparams')+                               ( \ ctx -> TLS.bye ctx >> TCP.close c ) $ \ ctx -> do+                    TLS.handshake ctx+                    tc <- TLS.tLsToConnection (ctx, sockAddr)+                    let tlsIs = TCP.source tc+                    tlsIs' <- decodeInputStream tlsIs+                    let auth = mkAuth db user pass charset greet+                    write tc (encodeToPacket 2 auth)+                    q <- readPacket tlsIs'+                    completeAuth tlsIs' (write tc) pass q tlsFullAuth+                    consumed <- newIORef True+                    let waitNotMandatoryOK = catch+                            (void (waitCommandReply tlsIs'))+                            ((\ _ -> return ()) :: SomeException -> IO ())+                        conn = MySQLConn tlsIs' (write tc)+                            (writeCommand COM_QUIT (write tc) >> waitNotMandatoryOK >> TCP.close tc)+                            consumed+                    return (greet, conn)+            else error "Database.MySQL.TLS: server doesn't support TLS connection"+  where+    connectWithBufferSize h p bs = TCP.connectSocket h p >>= TCP.socketToConnection bs+    write c a = TCP.send c $ Binary.runPut . Binary.put $ a++-- | Full auth handler for TLS connections: sends the cleartext password+-- as a NUL-terminated packet, which MySQL accepts over encrypted connections.+tlsFullAuth :: Word8 -> ByteString -> (Packet -> IO ()) -> InputStream Packet -> IO ()+tlsFullAuth seqN pass writePacket is = do+    let payload = pass `B.append` "\0"+        body = L.fromStrict payload+        pkt = Packet (fromIntegral (B.length payload)) seqN body+    writePacket pkt+    q <- readPacket is+    if isOK q+        then return ()+        else decodeFromPacket q >>= throwIO . ERRException
+ src/System/IO/Streams/TCP.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE CPP #-}++-- | This module provides convenience functions for interfacing raw tcp.+--+-- Please use 'E.bracket' or its friends to ensure exception safety.+--+-- This module is intended to be imported @qualified@, e.g.:+--+-- @+-- import           "Data.Connection"+-- import qualified "System.IO.Streams.TCP" as TCP+-- @+--+module System.IO.Streams.TCP+  ( TCPConnection+    -- * client+  , connect+  , connectSocket+  , socketToConnection+  , defaultChunkSize+    -- * server+  , bindAndListen+  , bindAndListenWith+  , accept+  , acceptWith+  ) where++import qualified Control.Exception         as E+import           Control.Monad+import           Data.Connection+import qualified Data.ByteString           as B+import qualified Data.ByteString.Lazy.Internal as L+import qualified Network.Socket            as N+import qualified Network.Socket.ByteString as NB+import qualified Network.Socket.ByteString.Lazy as NL+import qualified System.IO.Streams         as S+import           Foreign.Storable   (sizeOf)++addrAny :: N.HostAddress+#if MIN_VERSION_network(2,7,0)+addrAny = N.tupleToHostAddress (0,0,0,0)+#else+addrAny = N.iNADDR_ANY+#endif++-- | Type alias for tcp connection.+--+-- Normally you shouldn't use 'N.Socket' in 'connExtraInfo' directly, this field is+-- intend for used with 'N.setSocketOption' if you need to.+--+type TCPConnection = Connection (N.Socket, N.SockAddr)++-- | The chunk size used for I\/O, less the memory management overhead.+--+-- Currently set to 32k.+--+defaultChunkSize :: Int+defaultChunkSize = 32 * k - chunkOverhead+  where+    k = 1024+    chunkOverhead = 2 * sizeOf (undefined :: Int)++-- | Initiating an raw TCP connection to the given @('HostName', 'PortNumber')@ combination.+--+-- It use 'N.getAddrInfo' to resolve host/service name+-- with 'N.AI_ADDRCONFIG', 'N.AI_NUMERICSERV' hint set, so it should be able to+-- resolve both numeric IPv4/IPv6 hostname and domain name.+--+-- `TCP_NODELAY` are enabled by default. you can use 'N.setSocketOption' to adjust.+--+connectSocket :: N.HostName             -- ^ hostname to connect to+              -> N.PortNumber           -- ^ port number to connect to+              -> IO (N.Socket, N.SockAddr)+connectSocket host port = do+    (family, socketType, protocol, addr) <- resolveAddrInfo host port+    E.bracketOnError (N.socket family socketType protocol)+                     N.close+                     (\sock -> do N.connect sock addr+                                  N.setSocketOption sock N.NoDelay 1+                                  return (sock, addr)+                     )+  where+    resolveAddrInfo host' port' = do+        -- Partial function here OK, network will throw an exception rather than+        -- return the empty list here.+        (addrInfo:_) <- N.getAddrInfo (Just hints) (Just host') (Just $ show port')+        let family     = N.addrFamily addrInfo+        let socketType = N.addrSocketType addrInfo+        let protocol   = N.addrProtocol addrInfo+        let addr    = N.addrAddress addrInfo+        return (family, socketType, protocol, addr)+      where+        hints = N.defaultHints {+                N.addrFlags      = [N.AI_ADDRCONFIG, N.AI_NUMERICSERV]+            ,   N.addrSocketType = N.Stream+            }+    {-# INLINABLE resolveAddrInfo #-}++-- | Make a 'Connection' from a 'Socket' with given buffer size.+--+socketToConnection+    :: Int                      -- ^ receive buffer size+    -> (N.Socket, N.SockAddr)   -- ^ socket address pair+    -> IO TCPConnection+socketToConnection bufsiz (sock, addr) = do+    is <- S.makeInputStream $ do+        s <- NB.recv sock bufsiz+        return $! if B.null s then Nothing else Just s+    return (Connection is (send' sock) (N.close sock) (sock, addr))+  where+    send' _    (L.Empty) = return ()+    send' sock' (L.Chunk bs L.Empty) = unless (B.null bs) (NB.sendAll sock' bs)+    send' sock' lbs = NL.sendAll sock' lbs++-- | Connect to server using 'defaultChunkSize'.+--+connect :: N.HostName             -- ^ hostname to connect to+        -> N.PortNumber           -- ^ port number to connect to+        -> IO TCPConnection+connect host port = connectSocket host port >>= socketToConnection defaultChunkSize++-- | Bind and listen on port with a limit on connection count.+--+-- This function will set @SO_REUSEADDR@, @TCP_NODELAY@ before binding.+--+bindAndListen :: Int                 -- ^ connection limit+              -> N.PortNumber        -- ^ port number+              -> IO N.Socket+bindAndListen = bindAndListenWith $ \ sock -> do+    N.setSocketOption sock N.ReuseAddr 1+    N.setSocketOption sock N.NoDelay 1++-- | Bind and listen on port with a limit on connection count.+--+-- Note: The following socket options are inherited by a connected TCP socket from the listening socket:+--+-- @+-- SO_DEBUG+-- SO_DONTROUTE+-- SO_KEEPALIVE+-- SO_LINGER+-- SO_OOBINLINE+-- SO_RCVBUF+-- SO_RCVLOWAT+-- SO_SNDBUF+-- SO_SNDLOWAT+-- TCP_MAXSEG+-- TCP_NODELAY+-- @+--+bindAndListenWith :: (N.Socket -> IO ()) -- ^ set socket options before binding+                  -> Int                 -- ^ connection limit+                  -> N.PortNumber        -- ^ port number+                  -> IO N.Socket+bindAndListenWith f maxc port =+    E.bracketOnError (N.socket N.AF_INET N.Stream 0)+                     N.close+                     (\sock -> do f sock+                                  N.bind sock (N.SockAddrInet port addrAny)+                                  N.listen sock maxc+                                  return sock+                     )++-- | Accept a connection with 'defaultChunkSize'.+--+accept :: N.Socket -> IO TCPConnection+accept = acceptWith (socketToConnection defaultChunkSize)++-- | Accept a connection with user customization.+--+acceptWith :: ((N.Socket, N.SockAddr) -> IO TCPConnection) -- ^ set socket options, adjust receive buffer, etc.+           -> N.Socket+           -> IO TCPConnection+acceptWith f = f <=< N.accept
+ src/System/IO/Streams/TLS.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE ScopedTypeVariables #-}++-- | This module provides convenience functions for interfacing @tls@.+--+-- This module is intended to be imported @qualified@, e.g.:+--+-- @+-- import           "Data.Connection"+-- import qualified "System.IO.Streams.TLS" as TLS+-- @+--+module System.IO.Streams.TLS+  ( TLSConnection+    -- * client+  , connect+  , connectTLS+  , tLsToConnection+    -- * server+  , accept+    -- * re-export+  , module Data.TLSSetting+  ) where++import qualified Control.Exception     as E+import           Data.Connection+import qualified Data.ByteString       as B+import qualified Data.ByteString.Char8 as BC+import           Data.TLSSetting+import qualified Network.Socket        as N+import           Network.TLS           (ClientParams, Context, ServerParams)+import qualified Network.TLS           as TLS+import qualified System.IO.Streams     as Stream+import qualified System.IO.Streams.TCP as TCP+++-- | Type alias for tls connection.+--+-- Normally you shouldn't use 'TLS.Context' in 'connExtraInfo' directly.+--+type TLSConnection = Connection (TLS.Context, N.SockAddr)++-- | Make a 'Connection' from a 'Context'.+--+tLsToConnection :: (Context, N.SockAddr)    -- ^ TLS connection / socket address pair+                -> IO TLSConnection+tLsToConnection (ctx, addr) = do+    is <- Stream.makeInputStream input+    return (Connection is write (closeTLS ctx) (ctx, addr))+  where+    input = (do+        s <- TLS.recvData ctx+        return $! if B.null s then Nothing else Just s+        ) `E.catch` (\(_::E.SomeException) -> return Nothing)+    write s = TLS.sendData ctx s++-- | Close a TLS 'Context' and its underlying socket.+--+closeTLS :: Context -> IO ()+closeTLS ctx = (TLS.bye ctx >> TLS.contextClose ctx) -- sometimes socket was closed before 'TLS.bye'+    `E.catch` (\(_::E.SomeException) -> return ())   -- so we catch the 'Broken pipe' error here++-- | Convenience function for initiating an TLS connection to the given+-- @('HostName', 'PortNumber')@ combination.+--+-- This operation may throw 'TLS.TLSException' on failure.+--+connectTLS :: ClientParams         -- ^ check "Data.TLSSetting"+           -> Maybe String         -- ^ Optional certificate subject name, if set to 'Nothing'+                                   -- then we will try to verify 'HostName' as subject name+           -> N.HostName           -- ^ hostname to connect to+           -> N.PortNumber         -- ^ port number to connect to+           -> IO (Context, N.SockAddr)+connectTLS prms subname host port = do+    let subname' = maybe host id subname+        prms' = prms { TLS.clientServerIdentification = (subname', BC.pack (show port)) }+    (sock, addr) <- TCP.connectSocket host port+    E.bracketOnError (TLS.contextNew sock prms') closeTLS $ \ ctx -> do+        TLS.handshake ctx+        return (ctx, addr)++-- | Connect to server using TLS and return a 'Connection'.+--+connect :: ClientParams         -- ^ check "Data.TLSSetting"+        -> Maybe String         -- ^ Optional certificate subject name, if set to 'Nothing'+                                -- then we will try to verify 'HostName' as subject name+        -> N.HostName           -- ^ hostname to connect to+        -> N.PortNumber         -- ^ port number to connect to+        -> IO TLSConnection+connect prms subname host port = connectTLS prms subname host port >>= tLsToConnection++-- | Accept a new TLS connection from remote client with listening socket.+--+-- This operation may throw 'TLS.TLSException' on failure.+--+accept :: ServerParams              -- ^ check "Data.TLSSetting"+       -> N.Socket                  -- ^ the listening 'Socket'+       -> IO TLSConnection+accept prms sock = do+    (sock', addr) <- N.accept sock+    E.bracketOnError (TLS.contextNew sock' prms) closeTLS $ \ ctx -> do+        TLS.handshake ctx+        conn <- tLsToConnection (ctx, addr)+        return conn
+ test/Aeson.hs view
@@ -0,0 +1,338 @@+{-# LANGUAGE BangPatterns, CPP, OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-unused-binds #-}++module Aeson where++import Data.ByteString.Builder+  (Builder, byteString, toLazyByteString, charUtf8, word8)++import Control.Applicative (liftA2)+import Control.DeepSeq (NFData(..))+import Data.Attoparsec.ByteString.Char8 (Parser, char, endOfInput, scientific,+                                         skipSpace, string)+import Data.Bits ((.|.), shiftL)+import Data.ByteString (ByteString)+import Data.Char (chr)+import Data.Scientific (Scientific)+import Data.Text (Text)+import Data.Text.Encoding (decodeUtf8')+import Data.Vector as Vector (Vector, foldl', fromList)+import Data.Word (Word8)+import System.FilePath ((</>))+import qualified Data.Attoparsec.ByteString as A+import qualified Data.Attoparsec.Lazy as L+import qualified Data.Attoparsec.Zepto as Z+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Unsafe as B+import qualified Data.HashMap.Strict as H+import System.Directory (doesDirectoryExist)++#define BACKSLASH 92+#define CLOSE_CURLY 125+#define CLOSE_SQUARE 93+#define COMMA 44+#define DOUBLE_QUOTE 34+#define OPEN_CURLY 123+#define OPEN_SQUARE 91+#define C_0 48+#define C_9 57+#define C_A 65+#define C_F 70+#define C_a 97+#define C_f 102+#define C_n 110+#define C_t 116++pathTo :: String -> IO FilePath+pathTo wat = do+  exists <- doesDirectoryExist "bench"+  return $ if exists+           then "bench" </> wat+           else wat++data Result a = Error String+              | Success a+                deriving (Eq, Show)+++-- | A JSON \"object\" (key\/value map).+type Object = H.HashMap Text Value++-- | A JSON \"array\" (sequence).+type Array = Vector Value++-- | A JSON value represented as a Haskell value.+data Value = Object !Object+           | Array !Array+           | String !Text+           | Number !Scientific+           | Bool !Bool+           | Null+             deriving (Eq, Show)++instance NFData Value where+    rnf (Object o) = rnf o+    rnf (Array a)  = Vector.foldl' (\x y -> rnf y `seq` x) () a+    rnf (String s) = rnf s+    rnf (Number n) = rnf n+    rnf (Bool b)   = rnf b+    rnf Null       = ()++-- | Parse a top-level JSON value.  This must be either an object or+-- an array, per RFC 4627.+--+-- The conversion of a parsed value to a Haskell value is deferred+-- until the Haskell value is needed.  This may improve performance if+-- only a subset of the results of conversions are needed, but at a+-- cost in thunk allocation.+json :: Parser Value+json = json_ object_ array_++-- | Parse a top-level JSON value.  This must be either an object or+-- an array, per RFC 4627.+--+-- This is a strict version of 'json' which avoids building up thunks+-- during parsing; it performs all conversions immediately.  Prefer+-- this version if most of the JSON data needs to be accessed.+json' :: Parser Value+json' = json_ object_' array_'++json_ :: Parser Value -> Parser Value -> Parser Value+json_ obj ary = do+  w <- skipSpace *> A.satisfy (\w -> w == OPEN_CURLY || w == OPEN_SQUARE)+  if w == OPEN_CURLY+    then obj+    else ary+{-# INLINE json_ #-}++object_ :: Parser Value+object_ = {-# SCC "object_" #-} Object <$> objectValues jstring value++object_' :: Parser Value+object_' = {-# SCC "object_'" #-} do+  !vals <- objectValues jstring' value'+  return (Object vals)+ where+  jstring' = do+    !s <- jstring+    return s++objectValues :: Parser Text -> Parser Value -> Parser (H.HashMap Text Value)+objectValues str val = do+  skipSpace+  let pair = liftA2 (,) (str <* skipSpace) (char ':' *> skipSpace *> val)+  H.fromList <$> commaSeparated pair CLOSE_CURLY+{-# INLINE objectValues #-}++array_ :: Parser Value+array_ = {-# SCC "array_" #-} Array <$> arrayValues value++array_' :: Parser Value+array_' = {-# SCC "array_'" #-} do+  !vals <- arrayValues value'+  return (Array vals)++commaSeparated :: Parser a -> Word8 -> Parser [a]+commaSeparated item endByte = do+  w <- A.peekWord8'+  if w == endByte+    then A.anyWord8 >> return []+    else loop+  where+    loop = do+      v <- item <* skipSpace+      ch <- A.satisfy $ \w -> w == COMMA || w == endByte+      if ch == COMMA+        then skipSpace >> (v:) <$> loop+        else return [v]+{-# INLINE commaSeparated #-}++arrayValues :: Parser Value -> Parser (Vector Value)+arrayValues val = do+  skipSpace+  Vector.fromList <$> commaSeparated val CLOSE_SQUARE+{-# INLINE arrayValues #-}++-- | Parse any JSON value.  You should usually 'json' in preference to+-- this function, as this function relaxes the object-or-array+-- requirement of RFC 4627.+--+-- In particular, be careful in using this function if you think your+-- code might interoperate with Javascript.  A na&#xef;ve Javascript+-- library that parses JSON data using @eval@ is vulnerable to attack+-- unless the encoded data represents an object or an array.  JSON+-- implementations in other languages conform to that same restriction+-- to preserve interoperability and security.+value :: Parser Value+value = do+  w <- A.peekWord8'+  case w of+    DOUBLE_QUOTE  -> A.anyWord8 *> (String <$> jstring_)+    OPEN_CURLY    -> A.anyWord8 *> object_+    OPEN_SQUARE   -> A.anyWord8 *> array_+    C_f           -> string "false" *> pure (Bool False)+    C_t           -> string "true" *> pure (Bool True)+    C_n           -> string "null" *> pure Null+    _              | w >= 48 && w <= 57 || w == 45+                  -> Number <$> scientific+      | otherwise -> fail "not a valid json value"++-- | Strict version of 'value'. See also 'json''.+value' :: Parser Value+value' = do+  w <- A.peekWord8'+  case w of+    DOUBLE_QUOTE  -> do+                     !s <- A.anyWord8 *> jstring_+                     return (String s)+    OPEN_CURLY    -> A.anyWord8 *> object_'+    OPEN_SQUARE   -> A.anyWord8 *> array_'+    C_f           -> string "false" *> pure (Bool False)+    C_t           -> string "true" *> pure (Bool True)+    C_n           -> string "null" *> pure Null+    _              | w >= 48 && w <= 57 || w == 45+                  -> do+                     !n <- scientific+                     return (Number n)+      | otherwise -> fail "not a valid json value"++-- | Parse a quoted JSON string.+jstring :: Parser Text+jstring = A.word8 DOUBLE_QUOTE *> jstring_++-- | Parse a string without a leading quote.+jstring_ :: Parser Text+jstring_ = {-# SCC "jstring_" #-} do+  s <- A.scan False $ \s c -> if s then Just False+                                   else if c == DOUBLE_QUOTE+                                        then Nothing+                                        else Just (c == BACKSLASH)+  _ <- A.word8 DOUBLE_QUOTE+  s1 <- if BACKSLASH `B.elem` s+        then case Z.parse unescape s of+            Right r  -> return r+            Left err -> fail err+         else return s++  case decodeUtf8' s1 of+      Right r  -> return r+      Left err -> fail $ show err++{-# INLINE jstring_ #-}++unescape :: Z.Parser ByteString+unescape = toByteString <$> go mempty where+  go acc = do+    h <- Z.takeWhile (/=BACKSLASH)+    let rest = do+          start <- Z.take 2+          let !slash = B.unsafeHead start+              !t = B.unsafeIndex start 1+              escape = case B.findIndex (==t) "\"\\/ntbrfu" of+                         Just i -> i+                         _      -> 255+          if slash /= BACKSLASH || escape == 255+            then fail "invalid JSON escape sequence"+            else do+            let cont m = go (acc `mappend` byteString h `mappend` m)+                {-# INLINE cont #-}+            if t /= 117 -- 'u'+              then cont (word8 (B.unsafeIndex mapping escape))+              else do+                   a <- hexQuad+                   if a < 0xd800 || a > 0xdfff+                     then cont (charUtf8 (chr a))+                     else do+                       b <- Z.string "\\u" *> hexQuad+                       if a <= 0xdbff && b >= 0xdc00 && b <= 0xdfff+                         then let !c = ((a - 0xd800) `shiftL` 10) ++                                       (b - 0xdc00) + 0x10000+                              in cont (charUtf8 (chr c))+                         else fail "invalid UTF-16 surrogates"+    done <- Z.atEnd+    if done+      then return (acc `mappend` byteString h)+      else rest+  mapping = "\"\\/\n\t\b\r\f"++hexQuad :: Z.Parser Int+hexQuad = do+  s <- Z.take 4+  let hex n | w >= C_0 && w <= C_9 = w - C_0+            | w >= C_a && w <= C_f = w - 87+            | w >= C_A && w <= C_F = w - 55+            | otherwise          = 255+        where w = fromIntegral $ B.unsafeIndex s n+      a = hex 0; b = hex 1; c = hex 2; d = hex 3+  if (a .|. b .|. c .|. d) /= 255+    then return $! d .|. (c `shiftL` 4) .|. (b `shiftL` 8) .|. (a `shiftL` 12)+    else fail "invalid hex escape"++decodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString -> Maybe a+decodeWith p to s =+    case L.parse p s of+      L.Done _ v -> case to v of+                      Success a -> Just a+                      _         -> Nothing+      _          -> Nothing+{-# INLINE decodeWith #-}++decodeStrictWith :: Parser Value -> (Value -> Result a) -> B.ByteString+                 -> Maybe a+decodeStrictWith p to s =+    case either Error to (A.parseOnly p s) of+      Success a -> Just a+      Error _ -> Nothing+{-# INLINE decodeStrictWith #-}++eitherDecodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString+                 -> Either String a+eitherDecodeWith p to s =+    case L.parse p s of+      L.Done _ v -> case to v of+                      Success a -> Right a+                      Error msg -> Left msg+      L.Fail _ _ msg -> Left msg+{-# INLINE eitherDecodeWith #-}++eitherDecodeStrictWith :: Parser Value -> (Value -> Result a) -> B.ByteString+                       -> Either String a+eitherDecodeStrictWith p to s =+    case either Error to (A.parseOnly p s) of+      Success a -> Right a+      Error msg -> Left msg+{-# INLINE eitherDecodeStrictWith #-}++-- $lazy+--+-- The 'json' and 'value' parsers decouple identification from+-- conversion.  Identification occurs immediately (so that an invalid+-- JSON document can be rejected as early as possible), but conversion+-- to a Haskell value is deferred until that value is needed.+--+-- This decoupling can be time-efficient if only a smallish subset of+-- elements in a JSON value need to be inspected, since the cost of+-- conversion is zero for uninspected elements.  The trade off is an+-- increase in memory usage, due to allocation of thunks for values+-- that have not yet been converted.++-- $strict+--+-- The 'json'' and 'value'' parsers combine identification with+-- conversion.  They consume more CPU cycles up front, but have a+-- smaller memory footprint.++-- | Parse a top-level JSON value followed by optional whitespace and+-- end-of-input.  See also: 'json'.+jsonEOF :: Parser Value+jsonEOF = json <* skipSpace <* endOfInput++-- | Parse a top-level JSON value followed by optional whitespace and+-- end-of-input.  See also: 'json''.+jsonEOF' :: Parser Value+jsonEOF' = json' <* skipSpace <* endOfInput++toByteString :: Builder -> ByteString+toByteString = L.toStrict . toLazyByteString+{-# INLINE toByteString #-}
+ test/AesonBP.hs view
@@ -0,0 +1,284 @@+{-# LANGUAGE BangPatterns, CPP, OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-unused-binds #-}++module AesonBP where++import Data.ByteString.Builder+  (Builder, byteString, toLazyByteString, charUtf8, word8)++import Control.Applicative (liftA2)+import Data.Bits ((.|.), shiftL)+import Data.ByteString (ByteString)+import Data.Char (chr)+import Data.Text (Text)+import Data.Text.Encoding (decodeUtf8')+import Data.Vector as Vector (Vector, fromList)+import Data.Word (Word8)+import System.FilePath ((</>))+import qualified Data.Attoparsec.Zepto as Z+import Data.Binary.Get (Get)+import qualified Data.Binary.Parser as BP+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Unsafe as B+import qualified Data.HashMap.Strict as H+import System.Directory (doesDirectoryExist)+import Aeson (Value(..))++#define BACKSLASH 92+#define CLOSE_CURLY 125+#define CLOSE_SQUARE 93+#define COMMA 44+#define COLON 58+#define DOUBLE_QUOTE 34+#define OPEN_CURLY 123+#define OPEN_SQUARE 91+#define C_0 48+#define C_9 57+#define C_A 65+#define C_F 70+#define C_a 97+#define C_f 102+#define C_n 110+#define C_t 116++pathTo :: String -> IO FilePath+pathTo wat = do+  exists <- doesDirectoryExist "bench"+  return $ if exists+           then "bench" </> wat+           else wat++data Result a = Error String+              | Success a+                deriving (Eq, Show)+++-- | A JSON \"object\" (key\/value map).+type Object = H.HashMap Text Value++-- | A JSON \"array\" (sequence).+type Array = Vector Value++-- | Parse a top-level JSON value.  This must be either an object or+-- an array, per RFC 4627.+--+-- The conversion of a parsed value to a Haskell value is deferred+-- until the Haskell value is needed.  This may improve performance if+-- only a subset of the results of conversions are needed, but at a+-- cost in thunk allocation.+json :: Get Value+json = json_ object_ array_++-- | Parse a top-level JSON value.  This must be either an object or+-- an array, per RFC 4627.+--+-- This is a strict version of 'json' which avoids building up thunks+-- during parsing; it performs all conversions immediately.  Prefer+-- this version if most of the JSON data needs to be accessed.+json' :: Get Value+json' = json_ object_' array_'++json_ :: Get Value -> Get Value -> Get Value+json_ obj ary = do+  w <- BP.skipSpaces *> BP.satisfy (\w -> w == OPEN_CURLY || w == OPEN_SQUARE)+  if w == OPEN_CURLY+    then obj+    else ary+{-# INLINE json_ #-}++object_ :: Get Value+object_ = {-# SCC "object_" #-} Object <$> objectValues jstring value++object_' :: Get Value+object_' = {-# SCC "object_'" #-} do+  !vals <- objectValues jstring' value'+  return (Object vals)+ where+  jstring' = do+    !s <- jstring+    return s++objectValues :: Get Text -> Get Value -> Get (H.HashMap Text Value)+objectValues str val = do+  BP.skipSpaces+  let pair = liftA2 (,) (str <* BP.skipSpaces) (BP.word8 COLON *> BP.skipSpaces *> val)+  H.fromList <$> commaSeparated pair CLOSE_CURLY+{-# INLINE objectValues #-}++array_ :: Get Value+array_ = {-# SCC "array_" #-} Array <$> arrayValues value++array_' :: Get Value+array_' = {-# SCC "array_'" #-} do+  !vals <- arrayValues value'+  return (Array vals)++commaSeparated :: Get a -> Word8 -> Get [a]+commaSeparated item endByte = do+  w <- BP.peek+  if w == endByte+    then BP.skipN 1 >> return []+    else loop+  where+    loop = do+      v <- item <* BP.skipSpaces+      ch <- BP.satisfy $ \w -> w == COMMA || w == endByte+      if ch == COMMA+        then BP.skipSpaces >> (v:) <$> loop+        else return [v]+{-# INLINE commaSeparated #-}++arrayValues :: Get Value -> Get (Vector Value)+arrayValues val = do+  BP.skipSpaces+  Vector.fromList <$> commaSeparated val CLOSE_SQUARE+{-# INLINE arrayValues #-}++-- | Parse any JSON value.  You should usually 'json' in preference to+-- this function, as this function relaxes the object-or-array+-- requirement of RFC 4627.+--+-- In particular, be careful in using this function if you think your+-- code might interoperate with Javascript.  A na&#xef;ve Javascript+-- library that parses JSON data using @eval@ is vulnerable to attack+-- unless the encoded data represents an object or an array.  JSON+-- implementations in other languages conform to that same restriction+-- to preserve interoperability and security.+value :: Get Value+value = do+  w <- BP.peek+  case w of+    DOUBLE_QUOTE  -> BP.skipN 1 *> (String <$> jstring_)+    OPEN_CURLY    -> BP.skipN 1 *> object_+    OPEN_SQUARE   -> BP.skipN 1 *> array_+    C_f           -> BP.string "false" *> pure (Bool False)+    C_t           -> BP.string "true" *> pure (Bool True)+    C_n           -> BP.string "null" *> pure Null+    _              | w >= 48 && w <= 57 || w == 45+                  -> Number <$> BP.scientific+      | otherwise -> fail "not a valid json value"++-- | Strict version of 'value'. See also 'json''.+value' :: Get Value+value' = do+  w <- BP.peek+  case w of+    DOUBLE_QUOTE  -> do+                     !s <- BP.skipN 1 *> jstring_+                     return (String s)+    OPEN_CURLY    -> BP.skipN 1 *> object_'+    OPEN_SQUARE   -> BP.skipN 1 *> array_'+    C_f           -> BP.string "false" *> pure (Bool False)+    C_t           -> BP.string "true" *> pure (Bool True)+    C_n           -> BP.string "null" *> pure Null+    _              | w >= 48 && w <= 57 || w == 45+                  -> do+                     !n <- BP.scientific+                     return (Number n)+      | otherwise -> fail "not a valid json value"++-- | Parse a quoted JSON string.+jstring :: Get Text+jstring = BP.word8 DOUBLE_QUOTE *> jstring_++-- | Parse a string without a leading quote.+jstring_ :: Get Text+jstring_ = {-# SCC "jstring_" #-} do+  s <- BP.scan False $ \s c -> if s then Just False+                                   else if c == DOUBLE_QUOTE+                                        then Nothing+                                        else Just (c == BACKSLASH)+  BP.word8 DOUBLE_QUOTE+  s1 <- if BACKSLASH `B.elem` s+        then case Z.parse unescape s of+            Right r  -> return r+            Left err -> fail err+         else return s++  case decodeUtf8' s1 of+      Right r  -> return r+      Left err -> fail $ show err++{-# INLINE jstring_ #-}++unescape :: Z.Parser ByteString+unescape = toByteString <$> go mempty where+  go acc = do+    h <- Z.takeWhile (/=BACKSLASH)+    let rest = do+          start <- Z.take 2+          let !slash = B.unsafeHead start+              !t = B.unsafeIndex start 1+              escape = case B.findIndex (==t) "\"\\/ntbrfu" of+                         Just i -> i+                         _      -> 255+          if slash /= BACKSLASH || escape == 255+            then fail "invalid JSON escape sequence"+            else do+            let cont m = go (acc `mappend` byteString h `mappend` m)+                {-# INLINE cont #-}+            if t /= 117 -- 'u'+              then cont (word8 (B.unsafeIndex mapping escape))+              else do+                   a <- hexQuad+                   if a < 0xd800 || a > 0xdfff+                     then cont (charUtf8 (chr a))+                     else do+                       b <- Z.string "\\u" *> hexQuad+                       if a <= 0xdbff && b >= 0xdc00 && b <= 0xdfff+                         then let !c = ((a - 0xd800) `shiftL` 10) ++                                       (b - 0xdc00) + 0x10000+                              in cont (charUtf8 (chr c))+                         else fail "invalid UTF-16 surrogates"+    done <- Z.atEnd+    if done+      then return (acc `mappend` byteString h)+      else rest+  mapping = "\"\\/\n\t\b\r\f"++hexQuad :: Z.Parser Int+hexQuad = do+  s <- Z.take 4+  let hex n | w >= C_0 && w <= C_9 = w - C_0+            | w >= C_a && w <= C_f = w - 87+            | w >= C_A && w <= C_F = w - 55+            | otherwise          = 255+        where w = fromIntegral $ B.unsafeIndex s n+      a = hex 0; b = hex 1; c = hex 2; d = hex 3+  if (a .|. b .|. c .|. d) /= 255+    then return $! d .|. (c `shiftL` 4) .|. (b `shiftL` 8) .|. (a `shiftL` 12)+    else fail "invalid hex escape"++-- $lazy+--+-- The 'json' and 'value' parsers decouple identification from+-- conversion.  Identification occurs immediately (so that an invalid+-- JSON document can be rejected as early as possible), but conversion+-- to a Haskell value is deferred until that value is needed.+--+-- This decoupling can be time-efficient if only a smallish subset of+-- elements in a JSON value need to be inspected, since the cost of+-- conversion is zero for uninspected elements.  The trade off is an+-- increase in memory usage, due to allocation of thunks for values+-- that have not yet been converted.++-- $strict+--+-- The 'json'' and 'value'' parsers combine identification with+-- conversion.  They consume more CPU cycles up front, but have a+-- smaller memory footprint.++-- | Parse a top-level JSON value followed by optional whitespace and+-- end-of-input.  See also: 'json'.+jsonEOF :: Get Value+jsonEOF = json <* BP.skipSpaces++-- | Parse a top-level JSON value followed by optional whitespace and+-- end-of-input.  See also: 'json''.+jsonEOF' :: Get Value+jsonEOF' = json' <* BP.skipSpaces++toByteString :: Builder -> ByteString+toByteString = L.toStrict . toLazyByteString+{-# INLINE toByteString #-}
+ test/BoundsCheck.hs view
@@ -0,0 +1,140 @@+module BoundsCheck (tests) where++import qualified Data.ByteString             as B+import qualified Data.ByteString.Lazy        as L+import           Data.Binary.Put             (runPut, putWord8)+import           Data.Binary.Parser          (parseOnly)+import           Test.Tasty+import           Test.Tasty.HUnit++import           Database.MySQL.Protocol.ColumnDef+import           Database.MySQL.Protocol.MySQLValue (getTextField, MySQLValue)+import           Database.MySQL.Protocol.Packet (putLenEncInt)+import           Database.MySQL.BinLogProtocol.BinLogEvent+                    (FormatDescription(..), eventHeaderLen, BinLogEventType(..))+import           Database.MySQL.BinLogProtocol.BinLogValue (getBinLogField)+import           Database.MySQL.BinLogProtocol.BinLogMeta (BinLogMeta(..))++tests :: TestTree+tests = testGroup "bounds-check"+    [ testGroup "text-protocol" textProtocolTests+    , testGroup "binlog-value" binlogValueTests+    , testGroup "binlog-event" binlogEventTests+    ]++--------------------------------------------------------------------------------+-- Helpers++-- | Build a ColumnDef with the given field type and default flags.+mkColumnDef :: FieldType -> ColumnDef+mkColumnDef ft = ColumnDef+    { columnDB        = ""+    , columnTable     = ""+    , columnOrigTable = ""+    , columnName      = ""+    , columnOrigName  = ""+    , columnCharSet   = 63 -- binary+    , columnLength    = 0+    , columnType      = ft+    , columnFlags     = 0+    , columnDecimals  = 0+    }++-- | Encode a length-prefixed ByteString as the MySQL wire protocol does,+-- then run the given Get parser on it.+parseLenEncField :: ColumnDef -> B.ByteString -> Either String MySQLValue+parseLenEncField cd payload =+    let encoded = L.toStrict . runPut $ do+            putLenEncInt (B.length payload)+            mapM_ putWord8 (B.unpack payload)+    in parseOnly (getTextField cd) encoded++-- | Check that parsing yields a Left (failure), not a crash or garbage.+assertParseFailure :: String -> Either String a -> Assertion+assertParseFailure label result = case result of+    Left _  -> pure ()+    Right _ -> assertFailure (label ++ ": expected parse failure but got a result")++--------------------------------------------------------------------------------+-- Text protocol tests++textProtocolTests :: [TestTree]+textProtocolTests =+    [ testCase "timestamp: date-only no time part" $ do+        -- "2024-01-01" is 10 bytes. dateParser succeeds, then+        -- unsafeDrop 11 on a 10-byte string is UB.+        -- With "abc" this wouldn't trigger because readDecimal "abc" → Nothing+        -- short-circuits via Maybe's Applicative before unsafeDrop is forced.+        let cd = mkColumnDef mySQLTypeTimestamp+            result = parseLenEncField cd "2024-01-01"+        assertParseFailure "timestamp no time" result++    , testCase "timestamp: truncated time" $ do+        -- "2024-01-01 1" is 12 bytes. dateParser succeeds, unsafeDrop 11+        -- gives "1", timeParser reads hour=1, rest="", then unsafeTail+        -- on empty remainder is UB.+        let cd = mkColumnDef mySQLTypeTimestamp+            result = parseLenEncField cd "2024-01-01 1"+        assertParseFailure "timestamp truncated time" result++    , testCase "datetime: date-only no time part" $ do+        -- Same as timestamp: dateParser succeeds on "2024-01-01",+        -- then unsafeDrop 11 on 10-byte string is UB.+        let cd = mkColumnDef mySQLTypeDateTime+            result = parseLenEncField cd "2024-01-01"+        assertParseFailure "datetime no time" result++    , testCase "time: empty input" $ do+        -- TIME parser does unsafeIndex 0 on the payload; empty = UB+        let cd = mkColumnDef mySQLTypeTime+            result = parseLenEncField cd ""+        assertParseFailure "time empty" result++    , testCase "date: missing separator" $ do+        -- "2024" has no '-' separator; readDecimal consumes everything,+        -- then unsafeTail is called on an empty remainder+        let cd = mkColumnDef mySQLTypeDate+            result = parseLenEncField cd "2024"+        assertParseFailure "date missing sep" result++    , testCase "time: missing separator" $ do+        -- "12" has no ':' separator; readDecimal consumes it,+        -- then unsafeTail is called on empty remainder+        let cd = mkColumnDef mySQLTypeTime+            result = parseLenEncField cd "12"+        assertParseFailure "time missing sep" result+    ]++--------------------------------------------------------------------------------+-- BinLog value tests++binlogValueTests :: [TestTree]+binlogValueTests =+    [ testCase "NEWDECIMAL: precision < scale causes underflow" $ do+        -- precision=3, scale=10: (precision - scale) underflows Word8 to 249,+        -- producing a huge index into the 10-element sizeTable+        let meta = BINLOG_TYPE_NEWDECIMAL 3 10+            -- Provide some bytes so Get doesn't fail on "not enough input" first+            input = B.replicate 64 0x80+            result = parseOnly (getBinLogField meta) input+        assertParseFailure "NEWDECIMAL underflow" result+    ]++--------------------------------------------------------------------------------+-- BinLog event tests++binlogEventTests :: [TestTree]+binlogEventTests =+    [ testCase "eventHeaderLen: BINLOG_UNKNOWN_EVENT (negative index)" $ do+        -- fromEnum BINLOG_UNKNOWN_EVENT - 1 = -1, negative index into ByteString+        let fd = FormatDescription+                { fdVersion = 4+                , fdMySQLVersion = B.replicate 50 0+                , fdCreateTime = 0+                , fdEventHeaderLenVector = B.pack [19, 19, 19]  -- short vector+                }+            -- This should not crash; should return safe fallback+            result = eventHeaderLen fd BINLOG_UNKNOWN_EVENT+        -- After fix: returns 0 (safe fallback) instead of crashing+        assertEqual "unknown event should return 0" 0 result+    ]
+ test/CachingSha2.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE ScopedTypeVariables #-}++module CachingSha2 (tests) where++import Database.MySQL.Base+import qualified System.IO.Streams as Stream+import Test.Tasty+import Test.Tasty.HUnit++-- | These tests exercise two different authentication paths in 'completeAuth'.+-- Both tests connect and run @SELECT 1@, but the server-side auth protocol+-- differs based on which MySQL user is used. The users are created in+-- @nix/ci.nix@ (integrated-checks-mysql80) with different auth plugins:+--+-- * @testMySQLHaskellSha2@ — created with @caching_sha2_password@ (the MySQL 8.0+--   default). The client sends a SHA256 scramble, the server responds with+--   AuthMoreData (0x01, byte 2 = 0x03) indicating fast auth success.+--   The CI script pre-caches the verifier via a unix socket login so the+--   fast path is guaranteed.+--+-- * @testMySQLHaskellNative@ — created with @mysql_native_password@. The server+--   advertises @caching_sha2_password@ in its Greeting, so the client initially+--   sends a SHA256 scramble. The server then responds with AuthSwitchRequest+--   (0xFE) telling the client to re-authenticate using @mysql_native_password@+--   with a new salt. The client re-scrambles with SHA1 and sends the response.+tests :: TestTree+tests = testGroup "caching_sha2_password"+    [ testCaseSteps "SHA256 fast auth" $ \step -> do+        step "connecting as testMySQLHaskellSha2 (caching_sha2_password)..."+        (_, c) <- connectDetail defaultConnectInfo+            { ciUser = "testMySQLHaskellSha2"+            , ciPassword = "testPassword123"+            , ciDatabase = "testMySQLHaskell"+            }++        step "executing SELECT 1..."+        (_, is) <- query_ c "SELECT 1"+        Just row <- Stream.read is+        assertBool "SELECT 1 returns 1" (row == [MySQLInt32 1] || row == [MySQLInt64 1])+        Stream.skipToEof is++        close c++    , testCaseSteps "AuthSwitchRequest handling (mysql_native_password on sha2 server)" $ \step -> do+        step "connecting as testMySQLHaskellNative (mysql_native_password)..."+        (_, c) <- connectDetail defaultConnectInfo+            { ciUser = "testMySQLHaskellNative"+            , ciPassword = "nativePass123"+            , ciDatabase = "testMySQLHaskell"+            }++        step "executing SELECT 1..."+        (_, is) <- query_ c "SELECT 1"+        Just row <- Stream.read is+        assertBool "SELECT 1 returns 1" (row == [MySQLInt32 1] || row == [MySQLInt64 1])+        Stream.skipToEof is++        close c+    ]
test/ExecuteMany.hs view
@@ -3,11 +3,9 @@  module ExecuteMany where -import           Control.Applicative import           Data.Time.Calendar  (fromGregorian) import           Data.Time.LocalTime (LocalTime (..), TimeOfDay (..)) import           Database.MySQL.Base-import qualified System.IO.Streams   as Stream import           Test.Tasty.HUnit  tests :: MySQLConn -> Assertion
+ test/Integration.hs view
@@ -0,0 +1,42 @@+module Main (main) where++import qualified Data.ByteString as B+import           Database.MySQL.Base+import           System.Environment (lookupEnv)+import           Test.Tasty (defaultMain, testGroup)+import qualified CachingSha2+import qualified MysqlTests+import qualified RoundtripBit+import qualified RoundtripYear+import qualified SelectOne+import qualified TLSConnection+import qualified UnixSocket++main :: IO ()+main = do+    (greet, c) <- connectDetail defaultConnectInfo+        {ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell"}+    close c+    let ver = greetingVersion greet+        isMySql80 = "8." `B.isPrefixOf` ver+                 || "9." `B.isPrefixOf` ver++    -- Probe for a Unix domain socket (MYSQL_UNIX_SOCKET env var, then common paths).+    mSockPath <- UnixSocket.findSocketPath++    -- Probe for TLS CA certificate path (set in NixOS VM tests).+    mTlsCaPath <- lookupEnv "MYSQL_TLS_CA_PATH"++    defaultMain $ testGroup "mysql-integration" $+        [ SelectOne.tests+        , RoundtripBit.tests+        , RoundtripYear.tests+        , MysqlTests.tests+        ]+        -- caching_sha2_password is MySQL 8.0+ only (MariaDB does not support it).+        -- The sha2 test users are created by the nix CI config for the MySQL 8.0 VM.+        ++ [ CachingSha2.tests | isMySql80 ]+        -- Unix socket tests are included only when a socket file is found.+        ++ [ UnixSocket.tests p | Just p <- [mSockPath] ]+        -- TLS tests are included only when a CA certificate path is provided.+        ++ [ TLSConnection.tests p | Just p <- [mTlsCaPath] ]
+ test/JSON.hs view
@@ -0,0 +1,32 @@+module JSON where++import Control.Monad+import qualified Data.ByteString as B+import Test.Tasty.HUnit+import Test.Tasty (TestTree)+import System.Directory (getDirectoryContents, doesDirectoryExist)+import System.FilePath ((</>))+import qualified Aeson as A+import qualified Data.Attoparsec.ByteString as A+import qualified AesonBP as B+import qualified Data.Binary.Parser as B+import Data.List+++pathTo :: String -> IO FilePath+pathTo wat = do+  exists <- doesDirectoryExist "test"+  return $ if exists+           then "test" </> wat+           else wat++tests :: IO [TestTree]+tests = do+    path <- pathTo "json-data"+    names <- sort . filter (`notElem` [".", ".."]) <$> getDirectoryContents path+    forM names $ \name -> do+        bs <- B.readFile (path </> name)+        return $ testCase name $+            assertEqual name (A.parseOnly A.jsonEOF' bs) (B.parseOnly B.jsonEOF' bs)++
test/Main.hs view
@@ -1,185 +1,31 @@-{-# LANGUAGE ScopedTypeVariables #-}--module Main where+module Main (main) where -import qualified BinaryRow-import qualified BinaryRowNew-import qualified BinLog-import qualified BinLogNew-import           Control.Concurrent    (forkIO, threadDelay)-import           Control.Exception     (bracket, catch)-import           Control.Monad-import qualified Data.ByteString       as B-import           Database.MySQL.Base-import           Database.MySQL.BinLog-import           System.Environment-import qualified System.IO.Streams as Stream-import           Test.Tasty-import           Test.Tasty.HUnit-import qualified TextRow-import qualified ExecuteMany-import qualified TextRowNew+import qualified QC.ByteString as ByteString+import qualified QC.Combinator as Combinator+import Test.Tasty (defaultMain, testGroup)+import qualified JSON+import qualified Sha1Scramble+import qualified Sha256Scramble+import qualified Word24+import qualified TCPStreams+import qualified BoundsCheck  main :: IO ()--main = defaultMain $ testCaseSteps "mysql-haskell test suit" $ \step -> do--    step "preparing table..."-    (greet, c) <- connectDetail defaultConnectInfo {ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell"}--    let ver = greetingVersion greet-        isNew = "5.6" `B.isPrefixOf` ver-                || "5.7" `B.isPrefixOf` ver  -- from MySQL 5.6.4 and up-                                             -- TIME, DATETIME, and TIMESTAMP support fractional seconds---    execute_ c "DROP TABLE IF EXISTS test"-    execute_ c "DROP TABLE IF EXISTS test_new"--    execute_ c  "CREATE TABLE test(\-                \__id           INT,\-                \__bit          BIT(16),\-                \__tinyInt      TINYINT,\-                \__tinyIntU     TINYINT UNSIGNED,\-                \__smallInt     SMALLINT,\-                \__smallIntU    SMALLINT UNSIGNED,\-                \__mediumInt    MEDIUMINT,\-                \__mediumIntU   MEDIUMINT UNSIGNED,\-                \__int          INT,\-                \__intU         INT UNSIGNED,\-                \__bigInt       BIGINT,\-                \__bigIntU      BIGINT UNSIGNED,\-                \__decimal      DECIMAL(20,10),\-                \__float        FLOAT,\-                \__double       DOUBLE,\-                \__date         DATE,\-                \__datetime     DATETIME,\-                \__timestamp    TIMESTAMP NULL,\-                \__time         TIME,\-                \__year         YEAR(4),\-                \__char         CHAR(8),\-                \__varchar      VARCHAR(1024),\-                \__binary       BINARY(8),\-                \__varbinary    VARBINARY(1024),\-                \__tinyblob     TINYBLOB,\-                \__tinytext     TINYTEXT,\-                \__blob         BLOB(1000000),\-                \__text         TEXT(1000000),\-                \__enum         ENUM('foo', 'bar', 'qux'),\-                \__set          SET('foo', 'bar', 'qux')\-                \) CHARACTER SET utf8"--    resetTestTable c--    step "testing executeMany"-    ExecuteMany.tests c--    resetTestTable c--    step "testing text protocol"-    TextRow.tests c--    resetTestTable c--    step "testing binary protocol"-    BinaryRow.tests c--    resetTestTable c---    when isNew $ do-        execute_ c "CREATE TABLE test_new(\-                   \__id           INT,\-                   \__datetime     DATETIME(2),\-                   \__timestamp    TIMESTAMP(4) NULL,\-                   \__time         TIME(6)\-                   \) CHARACTER SET utf8"--        resetTest57Table c--        step "testing MySQL5.7 extra text protocol"-        TextRowNew.tests c--        resetTest57Table c--        step "testing MySQL5.7 extra binary protocol"-        BinaryRowNew.tests c--        void $ resetTest57Table c--    step "testing binlog protocol"--    if isNew-    then do-        forkIO BinLogNew.eventProducer-        BinLogNew.tests c-    else do-        forkIO BinLog.eventProducer-        BinLog.tests c--    close c--    (greet, c) <- connectDetail defaultConnectInfo {ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell"}-    execute_ c "SET PASSWORD = PASSWORD('123456abcdefg???')"-    close c--    let loginFailMsg = "ERRException (ERR {errCode = 1045, errState = \"28000\", \-            \errMsg = \"Access denied for user 'testMySQLHaskell'@'localhost' (using password: YES)\"})"--    (greet, c) <- connectDetail-        defaultConnectInfo {ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell", ciPassword = "123456abcdefg???"}-    execute_ c "SET PASSWORD = PASSWORD('')"-    close c--    catch-        (void $ connectDetail-                    defaultConnectInfo-                        {ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell", ciPassword = "wrongPassWord"})-        (\ (e :: ERRException) -> assertEqual "wrong password should fail to login" (show e) loginFailMsg)--  where-    resetTestTable c = do-            execute_ c  "DELETE FROM test WHERE __id=0"-            execute_ c  "INSERT INTO test VALUES(\-                    \0,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL,\-                    \NULL\-                    \)"--    resetTest57Table c = do-            execute_ c  "DELETE FROM test_new WHERE __id=0"-            execute_ c  "INSERT INTO test_new VALUES(\-                        \0,\-                        \NULL,\-                        \NULL,\-                        \NULL\-                        \)"--+main = do+    jsonTests <- JSON.tests+    defaultMain $ testGroup "tests" [+      testGroup "binary-parser" [+        testGroup "bs" ByteString.tests+      , testGroup "combinator" Combinator.tests+      , testGroup "JSON" jsonTests+      ],+      testGroup "word24"+         Word24.tests+      , testGroup "tcp-streams"+         [+           TCPStreams.tests+         ]+      , Sha1Scramble.tests+      , Sha256Scramble.tests+      , BoundsCheck.tests+      ]
+ test/MysqlTests.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE ScopedTypeVariables #-}++module MysqlTests(tests)  where++import qualified BinaryRow+import qualified BinaryRowNew+import qualified BinLog+import qualified BinLogNew+import           Control.Concurrent    (forkIO, threadDelay)+import           Control.Exception     (bracket, catch)+import           Control.Monad+import qualified Data.ByteString       as B+import           Database.MySQL.Base+import           Database.MySQL.BinLog+import           System.Environment+import qualified System.IO.Streams as Stream+import           Test.Tasty+import           Test.Tasty.HUnit+import qualified TextRow+import qualified ExecuteMany+import qualified TextRowNew++tests :: TestTree+tests = testCaseSteps "mysql-haskell test suit" $ \step -> do++    step "preparing table..."+    (greet, c) <- connectDetail defaultConnectInfo {ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell"}++    let ver = greetingVersion greet+        isOld = "5.0" `B.isPrefixOf` ver+                || "5.1" `B.isPrefixOf` ver+                || "5.5" `B.isPrefixOf` ver+        isNew = not isOld  -- MySQL 5.6+ and MariaDB 10+ support fractional seconds+                           -- in TIME, DATETIME, and TIMESTAMP columns+++    execute_ c "DROP TABLE IF EXISTS test"+    execute_ c "DROP TABLE IF EXISTS test_new"++    execute_ c  "CREATE TABLE test(\+                \__id           INT,\+                \__bit          BIT(16),\+                \__tinyInt      TINYINT,\+                \__tinyIntU     TINYINT UNSIGNED,\+                \__smallInt     SMALLINT,\+                \__smallIntU    SMALLINT UNSIGNED,\+                \__mediumInt    MEDIUMINT,\+                \__mediumIntU   MEDIUMINT UNSIGNED,\+                \__int          INT,\+                \__intU         INT UNSIGNED,\+                \__bigInt       BIGINT,\+                \__bigIntU      BIGINT UNSIGNED,\+                \__decimal      DECIMAL(20,10),\+                \__float        FLOAT,\+                \__double       DOUBLE,\+                \__date         DATE,\+                \__datetime     DATETIME,\+                \__timestamp    TIMESTAMP NULL,\+                \__time         TIME,\+                \__year         YEAR(4),\+                \__char         CHAR(8),\+                \__varchar      VARCHAR(1024),\+                \__binary       BINARY(8),\+                \__varbinary    VARBINARY(1024),\+                \__tinyblob     TINYBLOB,\+                \__tinytext     TINYTEXT,\+                \__blob         BLOB(1000000),\+                \__text         TEXT(1000000),\+                \__enum         ENUM('foo', 'bar', 'qux'),\+                \__set          SET('foo', 'bar', 'qux')\+                \) CHARACTER SET utf8"++    resetTestTable c++    step "testing executeMany"+    ExecuteMany.tests c++    resetTestTable c++    step "testing text protocol"+    TextRow.tests c++    resetTestTable c++    step "testing binary protocol"+    BinaryRow.tests c++    resetTestTable c+++    when isNew $ do+        execute_ c "CREATE TABLE test_new(\+                   \__id           INT,\+                   \__datetime     DATETIME(2),\+                   \__timestamp    TIMESTAMP(4) NULL,\+                   \__time         TIME(6)\+                   \) CHARACTER SET utf8"++        resetTest57Table c++        step "testing MySQL5.7 extra text protocol"+        TextRowNew.tests c++        resetTest57Table c++        step "testing MySQL5.7 extra binary protocol"+        BinaryRowNew.tests c++        void $ resetTest57Table c++    step "testing binlog protocol"++    if isNew+    then do+        forkIO BinLogNew.eventProducer+        BinLogNew.tests c+    else do+        forkIO BinLog.eventProducer+        BinLog.tests c++    close c++    step "testing password change"+    (_, c) <- connectDetail defaultConnectInfo {ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell"}+    -- ALTER USER works on both MariaDB and MySQL 8.0 (SET PASSWORD = PASSWORD('...') was removed in MySQL 8.0)+    execute_ c "ALTER USER 'testMySQLHaskell'@'localhost' IDENTIFIED BY '123456abcdefg???'"+    close c++    (_, c) <- connectDetail+        defaultConnectInfo {ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell", ciPassword = "123456abcdefg???"}+    execute_ c "ALTER USER 'testMySQLHaskell'@'localhost' IDENTIFIED BY ''"+    close c++    catch+        (void $ connectDetail+                    defaultConnectInfo+                        {ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell", ciPassword = "wrongPassWord"})+        (\ (e :: ERRException) -> do+            let ERRException err = e+            assertEqual "wrong password should fail with error 1045" 1045 (errCode err))++  where+    resetTestTable c = do+            execute_ c  "DELETE FROM test WHERE __id=0"+            execute_ c  "INSERT INTO test VALUES(\+                    \0,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL,\+                    \NULL\+                    \)"++    resetTest57Table c = do+            execute_ c  "DELETE FROM test_new WHERE __id=0"+            execute_ c  "INSERT INTO test_new VALUES(\+                        \0,\+                        \NULL,\+                        \NULL,\+                        \NULL\+                        \)"++
+ test/Orphans.hs view
@@ -0,0 +1,25 @@+{-# OPTIONS_GHC -Wno-orphans #-}++-- https://tech.freckle.com/2018/12/12/a-home-for-orphan-instances/+module Orphans where++import Test.QuickCheck++import Data.Int.Int24+import Data.Word.Word24++-- Arbitrary/CoArbitrary instances for Int24 and Word24++instance Arbitrary Int24 where+  arbitrary = arbitraryBoundedIntegral+  shrink = shrinkIntegral++instance CoArbitrary Int24 where+  coarbitrary = coarbitraryIntegral++instance Arbitrary Word24 where+  arbitrary = arbitraryBoundedIntegral+  shrink = shrinkIntegral++instance CoArbitrary Word24 where+  coarbitrary = coarbitraryIntegral
+ test/QC/ByteString.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE BangPatterns, CPP, OverloadedStrings #-}+module QC.ByteString (tests) where++import Data.Char (chr, ord)+import Data.Int (Int64)+import Data.Word (Word8)+import Prelude hiding (take, takeWhile)+import QC.Common (liftOp, parseBS, toStrictBS)+import Test.Tasty (TestTree)+import Test.Tasty.QuickCheck (testProperty)+import Test.QuickCheck+import qualified Data.Scientific as Sci+import qualified Data.ByteString.Builder.Scientific as Sci+import qualified Data.Binary.Parser as P+import qualified Data.ByteString as B+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Lazy.Char8 as L8++newtype ASCIIChar = ASCIIChar Char+    deriving (Eq, Ord, Show, Read)+instance Arbitrary ASCIIChar where+    arbitrary = ASCIIChar <$> choose ('\0', '\127')+    shrink (ASCIIChar c) = ASCIIChar <$> shrink c++-- Basic byte-level combinators.++satisfy :: Word8 -> L.ByteString -> Property+satisfy w s = parseBS (P.satisfy (<=w)) (L.cons w s) === Just w++satisfyWith :: ASCIIChar -> L.ByteString -> Property+satisfyWith (ASCIIChar c) s = parseBS (P.satisfyWith (chr . fromIntegral) (<=c))+                         (L.cons (fromIntegral (ord c)) s) === Just c++word8 :: Word8 -> L.ByteString -> Property+word8 w s = parseBS (P.word8 w *> pure w) (L.cons w s) === Just w++skipWord8 :: Word8 -> L.ByteString -> Property+skipWord8 w s =+  case (parseBS (P.skipWord8 (<w)) s, L.uncons s) of+    (Nothing, mcs) -> maybe (property True) (expectFailure . it) mcs+    (Just _,  mcs) -> maybe (property False) it mcs+  where it cs = liftOp "<" (<) (fst cs) w++anyWord8 :: L.ByteString -> Property+anyWord8 s+    | L.null s  = p === Nothing+    | otherwise = p === Just (L.head s)+  where p = parseBS P.anyWord8 s++peekMaybe :: L.ByteString -> Property+peekMaybe s+    | L.null s  = p === Just (Nothing, s)+    | otherwise = p === Just (Just (L.head s), s)+  where p = parseBS ((,) <$> P.peekMaybe <*> P.getRemainingLazyByteString) s++peek :: L.ByteString -> Property+peek s = parseBS P.peek s === (fst <$> L.uncons s)++string :: L.ByteString -> L.ByteString -> Property+string s t = parseBS (P.string s' *> pure s') (s `L.append` t) === Just s'+  where s' = toStrictBS s++strings :: L.ByteString -> L.ByteString -> L.ByteString -> Property+strings s t u =+    parseBS (P.string (toStrictBS s) >> (P.string t' *> pure t')) (L.concat [s,t,u])+    === Just t'+  where t' = toStrictBS t++skipWhile :: Word8 -> L.ByteString -> Property+skipWhile w s =+    let t = L.dropWhile (<=w) s+    in case P.runGetOrFail (P.skipWhile (<=w)) s of+         Right (t', _, _) -> t === t'+         Left  _          -> property False++takeCount :: Positive Int -> L.ByteString -> Property+takeCount (Positive k) s =+    case parseBS (P.getByteString k) s of+      Nothing -> liftOp ">" (>) (fromIntegral k) (L.length s)+      Just _s -> liftOp "<=" (<=) (fromIntegral k) (L.length s)++takeWhile :: Word8 -> L.ByteString -> Property+takeWhile w s =+    let (h,t) = L.span (==w) s+    in case P.runGetOrFail (P.takeWhile (==w)) s of+         Right (t', _, h') -> t === t' .&&. toStrictBS h === h'+         Left _            -> property False++take :: Int -> L.ByteString -> Property+take n s = maybe (property $ L.length s < fromIntegral n)+           (=== B.take n (toStrictBS s)) $+           parseBS (P.getByteString n) s++remaining :: L.ByteString -> Property+remaining s = maybe (property False) (=== s) .+                       parseBS P.getRemainingLazyByteString $ s++takeWhile1 :: Word8 -> L.ByteString -> Property+takeWhile1 w s =+    let s'    = L.cons w s+        (h,t) = L.span (<=w) s'+    in case P.runGetOrFail (P.takeWhile1 (<=w)) s' of+         Right (t', _, h') -> t === t' .&&. toStrictBS h === h'+         _                 -> property False++takeTill :: Word8 -> L.ByteString -> Property+takeTill w s =+    let (h,t) = L.break (==w) s+    in case P.runGetOrFail (P.takeTill (==w)) s of+         Right (t', _, h') -> t === t' .&&. toStrictBS h === h'+         _                 -> property False++takeWhile1_empty :: Property+takeWhile1_empty = parseBS (P.takeWhile1 undefined) L.empty === Nothing++endOfInput :: L.ByteString -> Property+endOfInput s = parseBS P.endOfInput s === if L.null s+                                          then Just ()+                                          else Nothing++endOfLine :: L.ByteString -> Property+endOfLine s =+  case (parseBS P.endOfLine s, L8.uncons s) of+    (Nothing, mcs) -> maybe (property True) (expectFailure . eol) mcs+    (Just _,  mcs) -> maybe (property False) eol mcs+  where eol (c,s') = c === '\n' .||.+                     (c, fst <$> L8.uncons s') === ('\r', Just '\n')++scan :: L.ByteString -> Positive Int64 -> Property+scan s (Positive k) = parseBS p s === Just (toStrictBS $ L.take k s)+  where p = P.scan k $ \ n _ ->+            if n > 0 then let !n' = n - 1 in Just n' else Nothing++decimal :: Integer -> Property+decimal d =+    let dBS = BB.toLazyByteString $ BB.integerDec d+    in parseBS (P.signed P.decimal) dBS === Just d++double :: Double -> Property+double d =+    let dBS = BB.toLazyByteString $ BB.doubleDec d+    in parseBS P.double dBS === Just d++scientific :: Sci.Scientific -> Property+scientific sci =+    let sciBS = BB.toLazyByteString $ Sci.formatScientificBuilder Sci.Generic Nothing sci+    in parseBS P.scientific sciBS === Just sci++tests :: [TestTree]+tests = [+      testProperty "anyWord8" anyWord8+    , testProperty "endOfInput" endOfInput+    , testProperty "endOfLine" endOfLine+    , testProperty "peekMaybe" peekMaybe+    , testProperty "peek" peek+    , testProperty "satisfy" satisfy+    , testProperty "satisfyWith" satisfyWith+    , testProperty "scan" scan+    , testProperty "skipWord8" skipWord8+    , testProperty "skipWhile" skipWhile+    , testProperty "string" string+    , testProperty "strings" strings+    , testProperty "take" take+    , testProperty "takeCount" takeCount+    , testProperty "remaining" remaining+    , testProperty "takeTill" takeTill+    , testProperty "takeWhile" takeWhile+    , testProperty "takeWhile1" takeWhile1+    , testProperty "takeWhile1_empty" takeWhile1_empty+    , testProperty "word8" word8+    , testProperty "decimal" decimal+    , testProperty "double" double+    , testProperty "scientific" scientific+  ]
+ test/QC/Combinator.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE CPP, OverloadedStrings #-}++module QC.Combinator where++import qualified Control.Monad as M (replicateM)+import Data.Maybe (fromJust, isJust)+import Data.Word (Word8)+import QC.Common (Repack, parseBS, repackBS, toLazyBS)+import Test.Tasty (TestTree)+import Test.Tasty.QuickCheck (testProperty)+import Test.QuickCheck+import qualified Data.Binary.Parser as P+import qualified Data.ByteString as B+import qualified Data.Foldable as Foldable (asum)++asum :: NonEmptyList (NonEmptyList Word8) -> Gen Property+asum (NonEmpty xs) = do+  let ys = map (B.pack . getNonEmpty) xs+  return . forAll (repackBS <$> arbitrary <*> elements ys) $+    maybe False (`elem` ys) . parseBS (Foldable.asum (map (\s -> P.string s *> pure s) ys))++replicateM :: Positive (Small Int) -> Repack -> B.ByteString -> Bool+replicateM (Positive (Small n)) rs s =+    (length <$> parseBS (M.replicateM n (P.string s)) input) == Just n+  where input = repackBS rs (B.concat (replicate (n+1) s))++lookAhead :: NonEmptyList Word8 -> Bool+lookAhead (NonEmpty xs) =+  let ys = B.pack xs+      withLookAheadThenConsume = (\x y -> (x, y)) <$> P.lookAhead (P.string ys) <*> P.string ys+      mr = parseBS withLookAheadThenConsume $ toLazyBS ys+  in isJust mr && fst (fromJust mr) == snd (fromJust mr)++tests :: [TestTree]+tests = [+    testProperty "asum" asum+  , testProperty "replicateM" replicateM+  , testProperty "lookAhead" lookAhead+  ]
+ test/QC/Common.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE CPP, FlexibleInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module QC.Common+    (+      ASCII(..)+    , parseBS+    , toLazyBS+    , toStrictBS+    , Repack+    , repackBS+    , repackBS_+    , liftOp+    ) where++import Data.Char (isAlpha)+import Test.QuickCheck+import Test.QuickCheck.Instances ()+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.Binary.Parser as P++parseBS :: P.Get r -> BL.ByteString -> Maybe r+parseBS p lbs = case P.parseLazy p lbs of+    Left _ -> Nothing+    Right v -> Just v++toStrictBS :: BL.ByteString -> B.ByteString+toStrictBS = B.concat . BL.toChunks++toLazyBS :: B.ByteString -> BL.ByteString+toLazyBS = BL.fromChunks . (:[])++newtype ASCII a = ASCII { fromASCII :: a }+                  deriving (Eq, Ord, Show)++instance Arbitrary (ASCII B.ByteString) where+    arbitrary = (ASCII . B.pack) <$> listOf (choose (0,127))+    shrink = map (ASCII . B.pack) . shrink . B.unpack . fromASCII++instance Arbitrary (ASCII BL.ByteString) where+    arbitrary = ASCII <$> (repackBS <$> arbitrary <*> (fromASCII <$> arbitrary))+    shrink = map (ASCII . BL.pack) . shrink . BL.unpack . fromASCII++type Repack = NonEmptyList (Positive (Small Int))++repackBS :: Repack -> B.ByteString -> BL.ByteString+repackBS (NonEmpty bs) =+    BL.fromChunks . repackBS_ (map (getSmall . getPositive) bs)++repackBS_ :: [Int] -> B.ByteString -> [B.ByteString]+repackBS_ = go . cycle+  where go (b:bs) s+          | B.null s = []+          | otherwise = let (h,t) = B.splitAt b s+                        in h : go bs t+        go _ _ = error "unpossible"++liftOp :: (Show a, Testable prop) =>+          String -> (a -> a -> prop) -> a -> a -> Property+liftOp name f x y = counterexample desc (f x y)+  where op = case name of+               (c:_) | isAlpha c -> " `" ++ name ++ "` "+                     | otherwise -> " " ++ name ++ " "+               _ -> " ??? "+        desc = "not (" ++ show x ++ op ++ show y ++ ")"
+ test/RoundtripBit.hs view
@@ -0,0 +1,46 @@+module RoundtripBit (tests) where++import Database.MySQL.Base+import qualified System.IO.Streams as Stream+import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests = testCaseSteps "roundtrip MySQLBit" $ \step -> do+    (_, c) <- connectDetail defaultConnectInfo+        { ciUser = "testMySQLHaskell"+        , ciDatabase = "testMySQLHaskell"+        }++    execute_ c "CREATE TEMPORARY TABLE test_bit (__id INT, __val BIT(16))"+    execute_ c "INSERT INTO test_bit VALUES (1, NULL)"++    step "roundtrip MySQLBit via binary protocol"+    updStmt <- prepareStmt c "UPDATE test_bit SET __val = ? WHERE __id = 1"+    selStmt <- prepareStmt c "SELECT __val FROM test_bit WHERE __id = 1"++    let bitVal = 43744 -- 0b1010101011100000+    executeStmt c updStmt [MySQLBit bitVal]++    (_, is) <- queryStmt c selStmt []+    Just [v] <- Stream.read is+    Stream.skipToEof is+    assertEqual "MySQLBit roundtrips through BIT(16)" (MySQLBit bitVal) v++    step "roundtrip MySQLBit zero"+    executeStmt c updStmt [MySQLBit 0]++    (_, is2) <- queryStmt c selStmt []+    Just [v2] <- Stream.read is2+    Stream.skipToEof is2+    assertEqual "MySQLBit 0 roundtrips" (MySQLBit 0) v2++    step "roundtrip MySQLBit max for BIT(16)"+    executeStmt c updStmt [MySQLBit 65535]++    (_, is3) <- queryStmt c selStmt []+    Just [v3] <- Stream.read is3+    Stream.skipToEof is3+    assertEqual "MySQLBit 65535 roundtrips" (MySQLBit 65535) v3++    close c
+ test/RoundtripYear.hs view
@@ -0,0 +1,53 @@+module RoundtripYear (tests) where++import Database.MySQL.Base+import qualified System.IO.Streams as Stream+import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests = testCaseSteps "roundtrip MySQLYear" $ \step -> do+    (_, c) <- connectDetail defaultConnectInfo+        { ciUser = "testMySQLHaskell"+        , ciDatabase = "testMySQLHaskell"+        }++    execute_ c "CREATE TEMPORARY TABLE test_year (__id INT, __val YEAR(4))"+    execute_ c "INSERT INTO test_year VALUES (1, NULL)"++    step "roundtrip MySQLYear via binary protocol"+    updStmt <- prepareStmt c "UPDATE test_year SET __val = ? WHERE __id = 1"+    selStmt <- prepareStmt c "SELECT __val FROM test_year WHERE __id = 1"++    executeStmt c updStmt [MySQLYear 1999]++    (_, is) <- queryStmt c selStmt []+    Just [v] <- Stream.read is+    Stream.skipToEof is+    assertEqual "MySQLYear 1999 roundtrips" (MySQLYear 1999) v++    step "roundtrip MySQLYear min (1901)"+    executeStmt c updStmt [MySQLYear 1901]++    (_, is2) <- queryStmt c selStmt []+    Just [v2] <- Stream.read is2+    Stream.skipToEof is2+    assertEqual "MySQLYear 1901 roundtrips" (MySQLYear 1901) v2++    step "roundtrip MySQLYear max (2155)"+    executeStmt c updStmt [MySQLYear 2155]++    (_, is3) <- queryStmt c selStmt []+    Just [v3] <- Stream.read is3+    Stream.skipToEof is3+    assertEqual "MySQLYear 2155 roundtrips" (MySQLYear 2155) v3++    step "roundtrip MySQLYear zero"+    executeStmt c updStmt [MySQLYear 0]++    (_, is4) <- queryStmt c selStmt []+    Just [v4] <- Stream.read is4+    Stream.skipToEof is4+    assertEqual "MySQLYear 0 roundtrips" (MySQLYear 0) v4++    close c
+ test/SelectOne.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE ScopedTypeVariables #-}++module SelectOne (tests) where++import Database.MySQL.Base+import qualified System.IO.Streams as Stream+import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests = testCaseSteps "select 1" $ \step -> do+    step "connecting..."+    (_, c) <- connectDetail defaultConnectInfo+        { ciUser = "testMySQLHaskell"+        , ciDatabase = "testMySQLHaskell"+        }++    step "executing SELECT 1..."+    (_, is) <- query_ c "SELECT 1"+    Just row <- Stream.read is+    -- MySQL 8.0 returns MySQLInt64 for integer literals, older versions return MySQLInt32+    assertBool "SELECT 1 returns 1" (row == [MySQLInt32 1] || row == [MySQLInt64 1])+    Stream.skipToEof is++    close c
+ test/Sha1Scramble.hs view
@@ -0,0 +1,49 @@+module Sha1Scramble (tests) where++import qualified Data.ByteString as B+import qualified Data.ByteString.Base16 as Base16+import           Data.ByteString.Char8 (pack)+import           Database.MySQL.Connection (scrambleSHA1)+import           Test.Tasty+import           Test.Tasty.HUnit++hexToBytes :: String -> B.ByteString+hexToBytes = Base16.decodeLenient . pack++tests :: TestTree+tests = testGroup "SHA1 Scramble"+    [ testCase "empty password returns empty" $ do+        let result = scrambleSHA1 "some_salt" ""+        assertEqual "empty password" B.empty result++    , testCase "non-empty password returns 20 bytes" $ do+        let result = scrambleSHA1 "12345678901234567890" "password"+        assertEqual "scramble length" 20 (B.length result)++    , testCase "different salts produce different scrambles" $ do+        let r1 = scrambleSHA1 "salt1_______________" "password"+            r2 = scrambleSHA1 "salt2_______________" "password"+        assertBool "different salts should produce different results" (r1 /= r2)++    , testCase "different passwords produce different scrambles" $ do+        let salt = "12345678901234567890"+            r1 = scrambleSHA1 salt "password1"+            r2 = scrambleSHA1 salt "password2"+        assertBool "different passwords should produce different results" (r1 /= r2)++    , testCase "scramble is deterministic" $ do+        let salt = "12345678901234567890"+            r1 = scrambleSHA1 salt "testPassword123"+            r2 = scrambleSHA1 salt "testPassword123"+        assertEqual "same inputs produce same output" r1 r2++    , testCase "golden: salt=12345678901234567890 pass=password" $ do+        let result = scrambleSHA1 "12345678901234567890" "password"+            expected = hexToBytes "1957dce2724282e018f40d905824cb6361f88d41"+        assertEqual "golden vector 1" expected result++    , testCase "golden: salt=ABCDEFGHIJKLMNOPQRST pass=secret" $ do+        let result = scrambleSHA1 "ABCDEFGHIJKLMNOPQRST" "secret"+            expected = hexToBytes "28441590674285e7d03cae7af237504797f70e91"+        assertEqual "golden vector 2" expected result+    ]
+ test/Sha256Scramble.hs view
@@ -0,0 +1,49 @@+module Sha256Scramble (tests) where++import qualified Data.ByteString as B+import qualified Data.ByteString.Base16 as Base16+import           Data.ByteString.Char8 (pack)+import           Database.MySQL.Connection (scrambleSHA256)+import           Test.Tasty+import           Test.Tasty.HUnit++hexToBytes :: String -> B.ByteString+hexToBytes = Base16.decodeLenient . pack++tests :: TestTree+tests = testGroup "SHA256 Scramble"+    [ testCase "empty password returns empty" $ do+        let result = scrambleSHA256 "some_salt" ""+        assertEqual "empty password" B.empty result++    , testCase "non-empty password returns 32 bytes" $ do+        let result = scrambleSHA256 "12345678901234567890" "password"+        assertEqual "scramble length" 32 (B.length result)++    , testCase "different salts produce different scrambles" $ do+        let r1 = scrambleSHA256 "salt1_______________" "password"+            r2 = scrambleSHA256 "salt2_______________" "password"+        assertBool "different salts should produce different results" (r1 /= r2)++    , testCase "different passwords produce different scrambles" $ do+        let salt = "12345678901234567890"+            r1 = scrambleSHA256 salt "password1"+            r2 = scrambleSHA256 salt "password2"+        assertBool "different passwords should produce different results" (r1 /= r2)++    , testCase "scramble is deterministic" $ do+        let salt = "12345678901234567890"+            r1 = scrambleSHA256 salt "testPassword123"+            r2 = scrambleSHA256 salt "testPassword123"+        assertEqual "same inputs produce same output" r1 r2++    , testCase "golden: salt=12345678901234567890 pass=password" $ do+        let result = scrambleSHA256 "12345678901234567890" "password"+            expected = hexToBytes "718d80fb92b693f7ee1fcad95bfe7a2be1f332ac2c3ec6cdc85893b65b240650"+        assertEqual "golden vector 1" expected result++    , testCase "golden: salt=ABCDEFGHIJKLMNOPQRST pass=secret" $ do+        let result = scrambleSHA256 "ABCDEFGHIJKLMNOPQRST" "secret"+            expected = hexToBytes "d721e183c1f036a196c1389201b8d53f38064a16f1d0923683ab886763152d75"+        assertEqual "golden vector 2" expected result+    ]
+ test/TCPStreams.hs view
@@ -0,0 +1,122 @@+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}++module TCPStreams (tests) where++------------------------------------------------------------------------------+import           Control.Concurrent             (forkIO, newEmptyMVar, putMVar,+                                                 takeMVar)+import qualified Network.Socket                 as N+import           System.Timeout                 (timeout)+import           Test.Tasty+import           Test.Tasty.HUnit+import qualified Data.ByteString                as B+import qualified Data.ByteString.Lazy           as L+------------------------------------------------------------------------------+import qualified Data.TLSSetting                as TLS+import           Data.Connection+import qualified System.IO.Streams              as Stream+import qualified System.IO.Streams.TCP          as TCP+import qualified System.IO.Streams.TLS          as TLS+------------------------------------------------------------------------------++import Test.Tasty.ExpectedFailure (ignoreTestBecause)++tests :: TestTree+tests = testGroup "tests" [ testGroup "TCP" tcpTests+        , testGroup "TLS"  tlsTests+        , testGroup "HTTPS" [testHTTPS]+        ]++------------------------------------------------------------------------------++tcpTests :: [TestTree]+tcpTests = [ testTCPSocket ]++testTCPSocket :: TestTree+testTCPSocket = testCase "network/socket" $+    N.withSocketsDo $ do+    x <- timeout (10 * 10^(6::Int)) go+    assertEqual "ok" (Just ()) x++  where+    go = do+        portMVar   <- newEmptyMVar+        resultMVar <- newEmptyMVar+        _ <- forkIO $ client portMVar resultMVar+        server portMVar+        l <- takeMVar resultMVar+        assertEqual "testSocket" l ["ok"]++    client mvar resultMVar = do+        _ <- takeMVar mvar+        conn <- TCP.connect "127.0.0.1" 8888+        send conn "ok"+        Stream.toList (source conn) >>= putMVar resultMVar+        close conn++    server mvar = do+        sock <- TCP.bindAndListen 1024 8888+        putMVar mvar ()+        conn <- TCP.accept sock+        req <- Stream.readExactly 2 (source conn)+        send conn (L.fromStrict req)+        close conn++------------------------------------------------------------------------------++tlsTests :: [TestTree]+tlsTests = [ testTLSSocket+             -- TODO disabled because won't work in a  nix container+             -- , testHTTPS+           ]++testTLSSocket :: TestTree+testTLSSocket = testCase "network/socket" $+    N.withSocketsDo $ do+    x <- timeout (10 * 10^(6::Int)) go+    assertEqual "ok" (Just ()) x++  where+    go = do+        portMVar   <- newEmptyMVar+        resultMVar <- newEmptyMVar+        _ <- forkIO $ client portMVar resultMVar+        server portMVar+        l <- takeMVar resultMVar+        assertEqual "testSocket" l ["ok"]++    client mvar resultMVar = do+        _ <- takeMVar mvar+        cp <- TLS.makeClientParams (TLS.CustomCAStore "./test/cert/ca.pem")+        conn <- TLS.connect cp (Just "Winter") "127.0.0.1" 8889+        send conn "ok"+        Stream.toList (source conn) >>= putMVar resultMVar+        close conn++    server mvar = do+        sp <- TLS.makeServerParams "./test/cert/server-cert.pem" [] "./test/cert/server-key.pem"+        sock <- TCP.bindAndListen 1024 8889+        putMVar mvar ()+        conn <- TLS.accept sp sock+        req <- Stream.readExactly 2 (source conn)+        send conn (L.fromStrict req)+        close conn++testHTTPS :: TestTree+testHTTPS =+  ignoreTestBecause "can't connect to socket in a nix container, the build becomes no longer reproducible." $+  testCase "network/https" $+    N.withSocketsDo $ do+    x <- timeout (10 * 10^(6::Int)) go+    assertEqual "ok" (Just 1024) x+  where+    go = do+        cp <- TLS.makeClientParams TLS.MozillaCAStore+        conn <- TLS.connect cp Nothing "www.bing.com" 443+        send conn ("GET / HTTP/1.1\r\n")+        send conn ("Host: www.bing.com\r\n")+        send conn ("\r\n")+        bs <- Stream.readExactly 1024 (source conn)+        close conn+        return (B.length bs)
+ test/TLSConnection.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE ScopedTypeVariables #-}++module TLSConnection (tests) where++import qualified Data.ByteString       as B+import qualified Data.Text             as T+import           Database.MySQL.Base+import qualified Database.MySQL.TLS    as TLS+import           Database.MySQL.TLS    (makeClientParams, TrustedCAStore(..))+import qualified System.IO.Streams     as Stream+import           Test.Tasty+import           Test.Tasty.HUnit++tests :: FilePath -> TestTree+tests caPath = testGroup "tls-connection"+    [ testCaseSteps "TLS connectDetail: SELECT 1" $ \step -> do+        step "creating TLS client params..."+        cparams <- makeClientParams (CustomCAStore caPath)++        step "connecting via TLS..."+        (greet, conn) <- TLS.connectDetail+            defaultConnectInfo { ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell" }+            (cparams, "Winter")++        step "checking greeting version..."+        let ver = greetingVersion greet+        assertBool "greeting version is not empty" (not $ B.null ver)++        step "executing SELECT 1..."+        (_, is) <- query_ conn "SELECT 1"+        Just row <- Stream.read is+        assertBool "SELECT 1 returns 1"+            (row == [MySQLInt32 1] || row == [MySQLInt64 1])+        Stream.skipToEof is++        close conn++    , testCaseSteps "TLS connection: verify encryption active" $ \step -> do+        step "creating TLS client params..."+        cparams <- makeClientParams (CustomCAStore caPath)++        step "connecting via TLS..."+        conn <- TLS.connect+            defaultConnectInfo { ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell" }+            (cparams, "Winter")++        step "checking SSL cipher..."+        (_, is) <- query_ conn "SHOW STATUS LIKE 'Ssl_cipher'"+        Just row <- Stream.read is+        case row of+            [_name, MySQLText cipher] ->+                assertBool "SSL cipher is not empty" (not $ T.null cipher)+            _ -> assertFailure ("unexpected row shape: " ++ show row)+        Stream.skipToEof is++        close conn++    , testCaseSteps "TLS connection: prepared statement roundtrip" $ \step -> do+        step "creating TLS client params..."+        cparams <- makeClientParams (CustomCAStore caPath)++        step "connecting via TLS..."+        conn <- TLS.connect+            defaultConnectInfo { ciUser = "testMySQLHaskell", ciDatabase = "testMySQLHaskell" }+            (cparams, "Winter")++        step "executing prepared statement..."+        stmt <- prepareStmt conn "SELECT ? + 1"+        (_, is) <- queryStmt conn stmt [MySQLInt32 41]+        Just row <- Stream.read is+        assertBool "41 + 1 = 42"+            (row == [MySQLInt32 42] || row == [MySQLInt64 42])+        Stream.skipToEof is++        close conn+    ]
test/TextRow.hs view
@@ -3,7 +3,6 @@  module TextRow where -import           Control.Applicative import           Data.Time.Calendar  (fromGregorian) import           Data.Time.LocalTime (LocalTime (..), TimeOfDay (..)) import           Database.MySQL.Base@@ -13,7 +12,7 @@  tests :: MySQLConn -> Assertion tests c = do-    (f, is) <- query_ c "SELECT * FROM test"+    (f, is1) <- query_ c "SELECT * FROM test"      assertEqual "decode Field types" (columnType <$> f)         [ mySQLTypeLong@@ -48,8 +47,8 @@         , mySQLTypeString         ] -    Just v <- Stream.read is-    assertEqual "decode NULL values" v+    Just v1 <- Stream.read is1+    assertEqual "decode NULL values" v1         [ MySQLInt32 0         , MySQLNull         , MySQLNull@@ -82,11 +81,11 @@         , MySQLNull         ] -    Stream.skipToEof is+    Stream.skipToEof is1      let bitV = 57514 -- 0b1110000010101010 -    execute_ c "UPDATE test SET \+    _ <- execute_ c "UPDATE test SET \                 \__bit        = b'1110000010101010'                    ,\                 \__tinyInt    = -128                                   ,\                 \__tinyIntU   = 255                                    ,\@@ -117,10 +116,10 @@                 \__enum       = 'foo'                                  ,\                 \__set        = 'foo,bar' WHERE __id=0" -    (_, is) <- query_ c "SELECT * FROM test"-    Just v <- Stream.read is+    (_, is2) <- query_ c "SELECT * FROM test"+    Just v2 <- Stream.read is2 -    assertEqual "decode text protocol" v+    assertEqual "decode text protocol" v2         [ MySQLInt32 0         , MySQLBit bitV         , MySQLInt8 (-128)@@ -153,15 +152,15 @@         , MySQLText "foo,bar"         ] -    Stream.skipToEof is+    Stream.skipToEof is2 -    (_, is') <- queryVector_ c "SELECT * FROM test"-    Just v' <- Stream.read is'-    Stream.skipToEof is'+    (_, is3) <- queryVector_ c "SELECT * FROM test"+    Just v3 <- Stream.read is3+    Stream.skipToEof is3 -    assertEqual "decode text protocol(queryVector_)" v (V.toList v')+    assertEqual "decode text protocol(queryVector_)" v2 (V.toList v3) -    execute c "UPDATE test SET \+    _ <- execute c "UPDATE test SET \             \__bit        = ?     ,\             \__tinyInt    = ?     ,\             \__tinyIntU   = ?     ,\@@ -222,10 +221,10 @@                 , MySQLText "foo,bar"                 ] -    (_, is) <- query_ c "SELECT * FROM test"-    Just v <- Stream.read is+    (_, is4) <- query_ c "SELECT * FROM test"+    Just v4 <- Stream.read is4 -    assertEqual "roundtrip text protocol" v+    assertEqual "roundtrip text protocol" v4         [ MySQLInt32 0         , MySQLBit bitV         , MySQLInt8 (-128)@@ -258,18 +257,18 @@         , MySQLText "foo,bar"         ] -    Stream.skipToEof is+    Stream.skipToEof is4  -    execute_ c "UPDATE test SET \+    _ <- execute_ c "UPDATE test SET \         \__mediumInt  = null         ,\         \__double     = null         ,\         \__text = null WHERE __id=0" -    (_, is) <- query_ c "SELECT * FROM test"-    Just v <- Stream.read is+    (_, is5) <- query_ c "SELECT * FROM test"+    Just v5 <- Stream.read is5 -    assertEqual "decode text protocol with null" v+    assertEqual "decode text protocol with null" v5         [ MySQLInt32 0         , MySQLBit bitV         , MySQLInt8 (-128)@@ -302,18 +301,18 @@         , MySQLText "foo,bar"         ] -    Stream.skipToEof is+    Stream.skipToEof is5 -    execute c "UPDATE test SET \+    _ <- execute c "UPDATE test SET \         \__decimal  = ?         ,\         \__date     = ?         ,\         \__timestamp = ? WHERE __id=0"         [MySQLNull, MySQLNull, MySQLNull] -    (_, is) <- query_ c "SELECT * FROM test"-    Just v <- Stream.read is+    (_, is6) <- query_ c "SELECT * FROM test"+    Just v6 <- Stream.read is6 -    assertEqual "roundtrip text protocol with null" v+    assertEqual "roundtrip text protocol with null" v6         [ MySQLInt32 0         , MySQLBit bitV         , MySQLInt8 (-128)@@ -346,47 +345,47 @@         , MySQLText "foo,bar"         ] -    Stream.skipToEof is+    Stream.skipToEof is6 -    execute_ c "UPDATE test SET \+    _ <- execute_ c "UPDATE test SET \         \__time       = '199:59:59'     ,\         \__year       = 0  WHERE __id=0" -    (_, is) <- query_ c "SELECT __time, __year FROM test"-    Just v <- Stream.read is+    (_, is7) <- query_ c "SELECT __time, __year FROM test"+    Just v7 <- Stream.read is7 -    assertEqual "decode text protocol 2" v+    assertEqual "decode text protocol 2" v7             [ MySQLTime 0 (TimeOfDay 199 59 59)             , MySQLYear 0             ] -    Stream.skipToEof is+    Stream.skipToEof is7 -    execute_ c "UPDATE test SET \+    _ <- execute_ c "UPDATE test SET \         \__text       = ''     ,\         \__blob       = ''  WHERE __id=0" -    (_, is) <- query_ c "SELECT __text, __blob FROM test"-    Just v <- Stream.read is+    (_, is8) <- query_ c "SELECT __text, __blob FROM test"+    Just v8 <- Stream.read is8 -    assertEqual "decode text protocol 3" v+    assertEqual "decode text protocol 3" v8             [ MySQLText ""             , MySQLBytes ""             ] -    Stream.skipToEof is+    Stream.skipToEof is8 -    execute c "UPDATE test SET \+    _ <- execute c "UPDATE test SET \         \__time       = ?     ,\         \__year       = ?  WHERE __id=0"         [ MySQLTime 0 (TimeOfDay 199 59 59), MySQLYear 0] -    (_, is) <- query_ c "SELECT __time, __year FROM test"-    Just v <- Stream.read is+    (_, is9) <- query_ c "SELECT __time, __year FROM test"+    Just v9 <- Stream.read is9 -    assertEqual "roundtrip text protocol 2" v+    assertEqual "roundtrip text protocol 2" v9             [ MySQLTime 0 (TimeOfDay 199 59 59)             , MySQLYear 0             ] -    Stream.skipToEof is+    Stream.skipToEof is9
test/TextRowNew.hs view
@@ -3,7 +3,6 @@  module TextRowNew where -import           Control.Applicative import           Data.Time.Calendar  (fromGregorian) import           Data.Time.LocalTime (LocalTime (..), TimeOfDay (..)) import           Database.MySQL.Base@@ -12,7 +11,7 @@  tests :: MySQLConn -> Assertion tests c = do-    (f, is) <- query_ c "SELECT * FROM test_new"+    (f, is5) <- query_ c "SELECT * FROM test_new"      assertEqual "decode Field types" (columnType <$> f)         [ mySQLTypeLong@@ -21,51 +20,51 @@         , mySQLTypeTime         ] -    Just v <- Stream.read is-    assertEqual "decode NULL values" v+    Just v1 <- Stream.read is5+    assertEqual "decode NULL values" v1         [ MySQLInt32 0         , MySQLNull         , MySQLNull         , MySQLNull         ] -    Stream.skipToEof is+    Stream.skipToEof is5 -    execute_ c "UPDATE test_new SET \+    _ <- execute_ c "UPDATE test_new SET \                 \__datetime   = '2016-08-08 17:25:59.12'                  ,\                 \__timestamp  = '2016-08-08 17:25:59.1234'                ,\                 \__time       = '-199:59:59.123456' WHERE __id=0" -    (_, is) <- query_ c "SELECT * FROM test_new"-    Just v <- Stream.read is+    (_, is4) <- query_ c "SELECT * FROM test_new"+    Just v2 <- Stream.read is4 -    assertEqual "decode text protocol" v+    assertEqual "decode text protocol" v2         [ MySQLInt32 0         , MySQLDateTime (LocalTime (fromGregorian 2016 08 08) (TimeOfDay 17 25 59.12))         , MySQLTimeStamp (LocalTime (fromGregorian 2016 08 08) (TimeOfDay 17 25 59.1234))         , MySQLTime 1 (TimeOfDay 199 59 59.123456)         ] -    Stream.skipToEof is+    Stream.skipToEof is4 -    execute_ c "UPDATE test_new SET \+    _ <- execute_ c "UPDATE test_new SET \                 \__datetime   = '2016-08-08 17:25:59.1'                  ,\                 \__timestamp  = '2016-08-08 17:25:59.12'                ,\                 \__time       = '199:59:59.1234' WHERE __id=0" -    (_, is) <- query_ c "SELECT * FROM test_new"-    Just v <- Stream.read is+    (_, is0) <- query_ c "SELECT * FROM test_new"+    Just v3 <- Stream.read is0 -    assertEqual "decode text protocol 2" v+    assertEqual "decode text protocol 2" v3         [ MySQLInt32 0         , MySQLDateTime (LocalTime (fromGregorian 2016 08 08) (TimeOfDay 17 25 59.1))         , MySQLTimeStamp (LocalTime (fromGregorian 2016 08 08) (TimeOfDay 17 25 59.12))         , MySQLTime 0 (TimeOfDay 199 59 59.1234)         ] -    Stream.skipToEof is+    Stream.skipToEof is0 -    execute c "UPDATE test_new SET \+    _ <- execute c "UPDATE test_new SET \             \__datetime   = ?     ,\             \__timestamp  = ?     ,\             \__time       = ?  WHERE __id=0"@@ -75,19 +74,19 @@                 ]  -    (_, is) <- query_ c "SELECT * FROM test_new"-    Just v <- Stream.read is+    (_, is1) <- query_ c "SELECT * FROM test_new"+    Just v4 <- Stream.read is1 -    assertEqual "roundtrip text protocol" v+    assertEqual "roundtrip text protocol" v4         [ MySQLInt32 0         , MySQLDateTime (LocalTime (fromGregorian 2016 08 08) (TimeOfDay 17 25 59.12))         , MySQLTimeStamp (LocalTime (fromGregorian 2016 08 08) (TimeOfDay 17 25 59.1234))         , MySQLTime 1 (TimeOfDay 199 59 59.123456)         ] -    Stream.skipToEof is+    Stream.skipToEof is1 -    execute c "UPDATE test_new SET \+    _ <- execute c "UPDATE test_new SET \             \__datetime   = ?     ,\             \__timestamp  = ?     ,\             \__time       = ?  WHERE __id=0"@@ -96,17 +95,17 @@                 , MySQLTime 0 (TimeOfDay 199 59 59.1234)                 ] -    (_, is) <- query_ c "SELECT * FROM test_new"-    Just v <- Stream.read is+    (_, is2) <- query_ c "SELECT * FROM test_new"+    Just v5 <- Stream.read is2 -    assertEqual "roundtrip text protocol 2" v+    assertEqual "roundtrip text protocol 2" v5         [ MySQLInt32 0         , MySQLDateTime (LocalTime (fromGregorian 2016 08 08) (TimeOfDay 17 25 59.1))         , MySQLTimeStamp (LocalTime (fromGregorian 2016 08 08) (TimeOfDay 17 25 59.12))         , MySQLTime 0 (TimeOfDay 199 59 59.1234)         ] -    Stream.skipToEof is+    Stream.skipToEof is2      let row0 =             [ MySQLInt32 0@@ -120,13 +119,13 @@             , MySQLTimeStamp (LocalTime (fromGregorian 2016 08 09) (TimeOfDay 18 25 59.12))             , MySQLTime 0 (TimeOfDay 299 59 59.1234)             ]-    execute c "UPDATE test_new SET \+    _ <- execute c "UPDATE test_new SET \             \__id         = ?     ,\             \__datetime   = ?     ,\             \__timestamp  = ?     ,\             \__time       = ?  WHERE __id=0"             row0-    execute c "INSERT INTO test_new VALUES(\+    _ <- execute c "INSERT INTO test_new VALUES(\             \?,\             \?,\             \?,\@@ -134,13 +133,13 @@             \)"             row1 -    (_, is) <- query c "SELECT * FROM test_new WHERE __id IN (?) ORDER BY __id" [Many [MySQLInt32 0, MySQLInt32 1]]-    Just v0 <- Stream.read is-    Just v1 <- Stream.read is+    (_, is3) <- query c "SELECT * FROM test_new WHERE __id IN (?) ORDER BY __id" [Many [MySQLInt32 0, MySQLInt32 1]]+    Just v6 <- Stream.read is3+    Just v7 <- Stream.read is3 -    assertEqual "select list of ids" [v0, v1] [row0, row1]+    assertEqual "select list of ids" [v6, v7] [row0, row1] -    Stream.skipToEof is-    execute_ c "DELETE FROM test_new where __id=1"+    Stream.skipToEof is3+    _ <- execute_ c "DELETE FROM test_new where __id=1"      return ()
+ test/UnixSocket.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE ScopedTypeVariables #-}++module UnixSocket (tests, findSocketPath) where++import qualified Data.ByteString       as B+import           Database.MySQL.Base+import qualified System.IO.Streams     as Stream+import           System.Directory      (doesFileExist)+import           System.Environment    (lookupEnv)+import           Test.Tasty+import           Test.Tasty.HUnit++-- | Common Unix socket paths for MySQL/MariaDB.+defaultSocketPaths :: [FilePath]+defaultSocketPaths =+    [ "/tmp/mysql.sock"                    -- macOS Homebrew+    , "/var/run/mysqld/mysqld.sock"        -- Debian/Ubuntu+    , "/run/mysqld/mysqld.sock"            -- NixOS, Arch+    , "/var/lib/mysql/mysql.sock"          -- RHEL/CentOS+    , "/tmp/mysqld.sock"                   -- some macOS installs+    ]++-- | Find the MySQL Unix socket path.  Checks the @MYSQL_UNIX_SOCKET@+-- environment variable first, then probes common default locations.+findSocketPath :: IO (Maybe FilePath)+findSocketPath = do+    envPath <- lookupEnv "MYSQL_UNIX_SOCKET"+    case envPath of+        Just p  -> do+            exists <- doesFileExist p+            return $ if exists then Just p else Nothing+        Nothing -> firstExisting defaultSocketPaths+  where+    firstExisting []     = return Nothing+    firstExisting (p:ps) = do+        exists <- doesFileExist p+        if exists then return (Just p) else firstExisting ps++tests :: FilePath -> TestTree+tests socketPath = testGroup "unix-socket"+    [ testCaseSteps "connectUnixSocket: SELECT 1" $ \step -> do+        step "connecting via unix socket..."+        c <- connectUnixSocket socketPath defaultConnectInfo+            { ciUser     = "testMySQLHaskell"+            , ciDatabase = "testMySQLHaskell"+            }++        step "executing SELECT 1..."+        (_, is) <- query_ c "SELECT 1"+        Just row <- Stream.read is+        assertBool "SELECT 1 returns 1"+            (row == [MySQLInt32 1] || row == [MySQLInt64 1])+        Stream.skipToEof is++        close c++    , testCaseSteps "connectUnixSocketDetail: returns greeting" $ \step -> do+        step "connecting via unix socket with detail..."+        (greet, c) <- connectUnixSocketDetail socketPath defaultConnectInfo+            { ciUser     = "testMySQLHaskell"+            , ciDatabase = "testMySQLHaskell"+            }++        step "checking greeting version..."+        let ver = greetingVersion greet+        assertBool "greeting version is not empty" (not $ B.null ver)++        step "executing query to verify connection..."+        (_, is) <- query_ c "SELECT 1 + 1"+        Just row <- Stream.read is+        assertBool "SELECT 1+1 returns 2"+            (row == [MySQLInt32 2] || row == [MySQLInt64 2])+        Stream.skipToEof is++        close c++    , testCaseSteps "unix socket: prepared statement roundtrip" $ \step -> do+        step "connecting via unix socket..."+        c <- connectUnixSocket socketPath defaultConnectInfo+            { ciUser     = "testMySQLHaskell"+            , ciDatabase = "testMySQLHaskell"+            }++        step "executing prepared statement..."+        stmt <- prepareStmt c "SELECT ? + 1"+        (_, is) <- queryStmt c stmt [MySQLInt32 41]+        Just row <- Stream.read is+        assertBool "41 + 1 = 42"+            (row == [MySQLInt32 42] || row == [MySQLInt64 42])+        Stream.skipToEof is++        close c+    ]
+ test/Word24.hs view
@@ -0,0 +1,442 @@+module Word24(tests) where++import Prelude as P++import Test.Tasty+import           Test.Tasty.QuickCheck    (testProperty)++import Test.QuickCheck hiding ((.&.))++import Orphans()+import Data.Int+import Data.Int.Int24+import Data.Word+import Data.Word.Word24+import Data.Bits+import Foreign.Storable+import GHC.Real++prop_enum3 :: Int -> Bool+prop_addIdent :: Word24 -> Bool+prop_multIdent :: Word24 -> Bool+prop_unsigned :: Word24 -> Bool+prop_smaller :: Word16 -> Bool+prop_show :: Word16 -> Bool+prop_read :: Word24 -> Bool+prop_adder :: Word16 -> Word16 -> Property+prop_negate :: Word24 -> Bool+prop_abs :: Word24 -> Bool+prop_signum :: Word24 -> Bool+prop_real :: Word24 -> Bool+prop_enum1 :: Word24 -> Property+prop_enum2 :: Word24 -> Property+prop_enum4 :: Word24 -> Property+prop_enum5 :: Word24 -> Word8 -> Bool+prop_enum6 :: Word24 -> Word24 -> Bool+prop_quot :: Word24 -> Word24 -> Bool+prop_rem :: Word24 -> Word24 -> Bool+prop_div :: Word24 -> Word24 -> Bool+prop_mod :: Word24 -> Word24 -> Bool+prop_quotrem :: Word24 -> Word24 -> Bool+prop_divmod :: Word24 -> Word24 -> Bool+prop_and :: Word16 -> Word16 -> Bool+prop_or :: Word16 -> Word16 -> Bool+prop_xor :: Word16 -> Word16 -> Bool+prop_xor_ident :: Word24 -> Word24 -> Bool+prop_shiftL :: Word24 -> Bool+prop_shiftR :: Word24 -> Property+prop_shiftR2 :: Word24 -> Int -> Property+prop_shiftL_ident :: Word24 -> Bool+prop_rotate :: Word24 -> Int -> Bool+prop_comp :: Word24 -> Bool+prop_byteSwap :: Word24 -> Bool+prop_clz :: Word24 -> Bool+prop_ctz :: Word24 -> Bool+prop_bit_ident :: Bits a => a -> NonNegative Int -> Bool+prop_sizeOf :: Word24 -> Bool+prop_align :: Word24 -> Bool+prop_addIdentI :: Int24 -> Bool+prop_multIdentI :: Int24 -> Bool+prop_smallerI :: Int16 -> Bool+prop_showI :: Int16 -> Bool+prop_readI :: Int24 -> Bool+prop_adderI :: Int16 -> Int16 -> Bool+prop_negateI :: Int24 -> Bool+prop_absI :: Int24 -> Bool+prop_signumI :: Int24 -> Bool+prop_realI :: Int24 -> Bool+prop_enum1I :: Int24 -> Property+prop_enum2I :: Int24 -> Property+prop_enum3I :: Int -> Bool+prop_enum4I :: Int24 -> Property+prop_enum5I :: Int24 -> Word8 -> Bool+prop_enum6I :: Int24 -> Int24 -> Bool+prop_quotI :: Int24 -> Int24 -> Bool+prop_remI :: Int24 -> Int24 -> Bool+prop_divI :: Int24 -> Int24 -> Bool+prop_modI :: Int24 -> Int24 -> Bool++-- ----------------------------------------+-- Word24 Properties++prop_addIdent a = a - a == 0++prop_multIdent a = a * 1 == a++prop_unsigned a = a >= 0++prop_smaller a = (fromIntegral ((fromIntegral a) :: Word24) :: Word16) == a++prop_show a = show a == show (fromIntegral a :: Word24)++prop_read a = a == (read . show) a++prop_adder a b = (a < ub) && (b < ub) ==>+                 fromIntegral (a + b) ==+                 ((fromIntegral a + fromIntegral b) :: Word24)+     where+        ub :: Word16+        ub = maxBound `div` 2++prop_negate a = a == negate (negate a)++prop_abs a = a == abs a++prop_signum a = if a == 0 then signum a == a else signum a == 1++prop_real a = let r = toRational a in numerator r == fromIntegral a++-- Word24 Enum properties+prop_enum1 a = a < maxBound ==> succ a == a + 1++prop_enum2 a = a > minBound ==> pred a == a - 1++prop_enum3 a = let a' = abs a in+               toEnum a' == fromIntegral @_ @Integer a'++prop_enum4 a = a < maxBound ==> take 2 (enumFrom a) == [a, a+1]++prop_enum5 a b = let b' = fromIntegral b in+                 enumFromTo a (a + b') ==+                 map fromIntegral (enumFromTo (fromIntegral a :: Integer)+                                             (fromIntegral (a + b') :: Integer))++prop_enum6 a b = take 2 (enumFromThen a b) == [a,b]++-- Word24 Integral properties+prop_quot a b =+  quot a b == fromIntegral (quot (fromIntegral a :: Word32) (fromIntegral b :: Word32))++prop_rem a b =+  rem a b == fromIntegral (rem (fromIntegral a :: Word32) (fromIntegral b :: Word32))++prop_div a b =+  div a b == fromIntegral (div (fromIntegral a :: Word32) (fromIntegral b :: Word32))++prop_mod a b =+  mod a b == fromIntegral (mod (fromIntegral a :: Word32) (fromIntegral b :: Word32))++prop_quotrem a b = let (j, k) = quotRem a b in+  a == (b * j) + k++prop_divmod a b =+  divMod a b == (div a b, mod a b)++-- binary Word properties+prop_and a b = (a .&. b) == fromIntegral ( (fromIntegral a :: Word24) .&. (fromIntegral b :: Word24))++prop_or a b = (a .|. b) == fromIntegral ( (fromIntegral a :: Word24) .|. (fromIntegral b :: Word24))++prop_xor a b = (a `xor` b) == fromIntegral ( (fromIntegral a :: Word24) `xor` (fromIntegral b :: Word24))++prop_xor_ident a b = (a `xor` b) `xor` b == a++prop_shiftL a = a `shiftL` 1 == a * 2++prop_shiftR a = a < maxBound `div` 2 ==>+  (a * 2) `shift` (-1) == a++prop_shiftR2 a n = n >= 0 ==> a `shiftR` n == a `shift` (negate n)++prop_shiftL_ident a = a `shiftL` 0 == a++prop_rotate a b = (a `rotate` b) `rotate` (negate b) == a++prop_comp a = complement (complement a) == a++prop_byteSwap a = byteSwap24 (byteSwap24 a) == a++prop_clz a = countLeadingZeros a == countLeadingZeros' a+  where+    countLeadingZeros' :: Word24 -> Int+    countLeadingZeros' x = (w-1) - go (w-1)+      where+        go i | i < 0       = i -- no bit set+             | testBit x i = i+             | otherwise   = go (i-1)++        w = finiteBitSize x++prop_ctz a = countTrailingZeros a == countTrailingZeros' a+  where+    countTrailingZeros' :: Word24 -> Int+    countTrailingZeros' x = go 0+      where+        go i | i >= w      = i+             | testBit x i = i+             | otherwise   = go (i+1)+        w = finiteBitSize x++prop_bit_ident q (NonNegative j) = testBit (bit j `asTypeOf` q) j == (j < 24)++prop_popCount :: (Integral a1, Num a2, FiniteBits a1,+                        FiniteBits a2) =>+                       a1 -> a2 -> a1 -> Bool+prop_popCount s t a = if a >= 0+  then popCount (a `asTypeOf` s) == popCount (fromIntegral a `asTypeOf` t)+  else+    finiteBitSize s - popCount (a `asTypeOf` s) == finiteBitSize t - popCount (fromIntegral a `asTypeOf` t)++-- Word Storable properties+prop_sizeOf a = sizeOf a == 3++prop_align a = alignment a == 3++++-- ----------------------------------------+-- Int24 Properties++prop_addIdentI a = a - a == 0++prop_multIdentI a = a * 1 == a++prop_smallerI a = (fromIntegral ((fromIntegral a) :: Int24) :: Int16) == a++prop_showI a = show a == show (fromIntegral a :: Int24)++prop_readI a = a == (read . show) a++prop_adderI a b = ((fromIntegral a + fromIntegral b) :: Int) ==+                  fromIntegral ((fromIntegral a + fromIntegral b) :: Int24)++prop_negateI a = a == negate (negate a)++prop_absI a = if a >= 0 then a == abs a else a == negate (abs a)++prop_signumI a = signum a == fromIntegral (signum (fromIntegral a :: Int))++prop_realI a = let r = toRational a in numerator r == fromIntegral a++-- Int24 Enum Properties+prop_enum1I a = a < maxBound ==> succ a == a + 1++prop_enum2I a = a > minBound ==> pred a == a - 1++prop_enum3I a = let a' = abs a in+               toEnum a' == fromIntegral @_ @Integer a'++prop_enum4I a = a < maxBound ==> take 2 (enumFrom a) == [a, a+1]++prop_enum5I a b = let b' = fromIntegral b in+                 enumFromTo a (a + b') ==+                 map fromIntegral (enumFromTo (fromIntegral a :: Integer)+                                             (fromIntegral (a + b') :: Integer))++prop_enum6I a b = take 2 (enumFromThen a b) == [a,b]++-- Int24 Integral properties+prop_quotI a b =+  quot a b == fromIntegral (quot (fromIntegral a :: Int32) (fromIntegral b :: Int32))++prop_remI a b =+  rem a b == fromIntegral (rem (fromIntegral a :: Int32) (fromIntegral b :: Int32))++prop_divI a b =+  div a b == fromIntegral (div (fromIntegral a :: Int32) (fromIntegral b :: Int32))++prop_modI a b =+  mod a b == fromIntegral (mod (fromIntegral a :: Int32) (fromIntegral b :: Int32))++prop_quotremI :: Int24 -> Int24 -> Bool+prop_quotremI a b = let (j, k) = quotRem a b in+  a == (b * j) + k++prop_divmodI :: Int24 -> Int24 -> Bool+prop_divmodI a b =+  divMod a b == (div a b, mod a b)+++-- binary Int properties+prop_andI :: Int16 -> Int16 -> Bool+prop_andI a b = (a .&. b) == fromIntegral ( (fromIntegral a :: Int24) .&. (fromIntegral b :: Int24))++prop_orI :: Int16 -> Int16 -> Bool+prop_orI a b = (a .|. b) == fromIntegral ( (fromIntegral a :: Int24) .|. (fromIntegral b :: Int24))++prop_xorI :: Int16 -> Int16 -> Bool+prop_xorI a b = (a `xor` b) == fromIntegral ( (fromIntegral a :: Int24) `xor` (fromIntegral b :: Int24))++prop_xor_identI :: Int24 -> Int24 -> Bool+prop_xor_identI a b = (a `xor` b) `xor` b == a++prop_shiftLI :: Int24 -> Bool+prop_shiftLI a = a `shiftL` 1 == a * 2++prop_shiftL_identI :: Int24 -> Bool+prop_shiftL_identI a = a `shiftL` 0 == a++prop_shiftRI :: Int24 -> Property+prop_shiftRI a = (a < maxBound `div` 2) && (a > minBound `div` 2) ==>+  (a * 2) `shift` (-1) == a++prop_shiftR2I :: Int24 -> Int -> Property+prop_shiftR2I a n = n >= 0 ==> a `shiftR` n == a `shift` (negate n)++prop_rotateI :: Int24 -> Int -> Bool+prop_rotateI a b = (a `rotate` b) `rotate` (negate b) == a++prop_compI :: Int24 -> Bool+prop_compI a = complement (complement a) == a++prop_clzI :: Int24 -> Bool+prop_clzI a = countLeadingZeros a == countLeadingZeros' a+  where+    countLeadingZeros' :: Int24 -> Int+    countLeadingZeros' x = (w-1) - go (w-1)+      where+        go i | i < 0       = i -- no bit set+             | testBit x i = i+             | otherwise   = go (i-1)++        w = finiteBitSize x++prop_ctzI :: Int24 -> Bool+prop_ctzI a = countTrailingZeros a == countTrailingZeros' a+  where+    countTrailingZeros' :: Int24 -> Int+    countTrailingZeros' x = go 0+      where+        go i | i >= w      = i+             | testBit x i = i+             | otherwise   = go (i+1)+        w = finiteBitSize x++-- Int Storable properties+prop_sizeOfI :: Int24 -> Bool+prop_sizeOfI a = sizeOf a == 3++prop_alignI :: Int24 -> Bool+prop_alignI a = alignment a == 3+++-- ----------------------------------------+-- tests+tests :: [TestTree]+tests = [+ testGroup "Word24"+  [ testGroup "basic" [+    testProperty "add. identity" prop_addIdent+    ,testProperty "mult. identity" prop_multIdent+    ,testProperty "unsigned" prop_unsigned+    ,testProperty "Word16/Word24 conversion" prop_smaller+    ,testProperty "Show" prop_show+    ,testProperty "Read" prop_read+    ,testProperty "addition" prop_adder+    ,testProperty "negate identity" prop_negate+    ,testProperty "absolute value" prop_abs+    ,testProperty "signum" prop_signum+    ,testProperty "Real identity" prop_real+    ]+  ,testGroup "Integral instance" [+    testProperty  "quot" prop_quot+    ,testProperty "rem" prop_rem+    ,testProperty "div" prop_div+    ,testProperty "mod" prop_mod+    ,testProperty "quotRem" prop_quotrem+    ,testProperty "divmod" prop_divmod+    ]+  ,testGroup "Enum instance" [+    testProperty "enum succ" prop_enum1+    ,testProperty "enum pred" prop_enum2+    ,testProperty "toEnum" prop_enum3+    ,testProperty "enumFrom " prop_enum4+    ,testProperty "enumFromTo" prop_enum5+    ,testProperty "enumFromThen" prop_enum6+    ]+  ,testGroup "Bits instance" [+    testProperty "binary and" prop_and+    ,testProperty "binary or" prop_or+    ,testProperty "binary xor" prop_xor+    ,testProperty "binary xor identity" prop_xor_ident+    ,testProperty "binary shiftL" prop_shiftL+    ,testProperty "binary shiftL identity" prop_shiftL_ident+    ,testProperty "binary shift right" prop_shiftR+    ,testProperty "binary shiftR" prop_shiftR2+    ,testProperty "binary rotate" prop_rotate+    ,testProperty "binary complement" prop_comp+    ,testProperty "binary byteSwap24" prop_byteSwap+    ,testProperty "binary countLeadingZeros" prop_clz+    ,testProperty "binary countTrailingZeros" prop_ctz+    ,testProperty "binary countTrailingZeros 0" (prop_ctz (0::Word24))+    ,testProperty "bit/testBit" (prop_bit_ident (0::Word24))+    ,testProperty "popCount"    (prop_popCount (0::Word24) (0::Word))+    ]+  ,testGroup "Storable instance" [+    testProperty  "sizeOf Word24" prop_sizeOf+    ,testProperty "aligntment" prop_align+    ]+  ]+ ,testGroup "Int24"+  [testGroup "basic" [+    testProperty "add. identity" prop_addIdentI+    ,testProperty "mult. identity" prop_multIdentI+    ,testProperty "Int16/Int24 conversion" prop_smallerI+    ,testProperty "Show" prop_showI+    ,testProperty "Read" prop_readI+    ,testProperty "addition" prop_adderI+    ,testProperty "negate identity" prop_negateI+    ,testProperty "absolute value" prop_absI+    ,testProperty "signum" prop_signumI+    ,testProperty "Real identity" prop_realI+    ]+  ,testGroup "Integral instance" [+    testProperty  "quot" prop_quotI+    ,testProperty "rem" prop_remI+    ,testProperty "div" prop_divI+    ,testProperty "mod" prop_modI+    ,testProperty "quotRem" prop_quotremI+    ,testProperty "divmod" prop_divmodI+    ]+  ,testGroup "Enum instance" [+    testProperty "enum succ" prop_enum1I+    ,testProperty "enum pred" prop_enum2I+    ,testProperty "toEnum" prop_enum3I+    ,testProperty "enumFrom " prop_enum4I+    ,testProperty "enumFromTo" prop_enum5I+    ,testProperty "enumFromThen" prop_enum6I+    ]+  ,testGroup "Bits instance" [+    testProperty "binary and" prop_andI+    ,testProperty "binary or" prop_orI+    ,testProperty "binary xor" prop_xorI+    ,testProperty "binary xor identity" prop_xor_identI+    ,testProperty "binary shiftL" prop_shiftLI+    ,testProperty "binary shiftL identity" prop_shiftL_identI+    ,testProperty "binary shift right" prop_shiftRI+    ,testProperty "binary shiftR" prop_shiftR2I+    ,testProperty "binary rotate" prop_rotateI+    ,testProperty "binary complement" prop_compI+    ,testProperty "binary countLeadingZeros" prop_clzI+    ,testProperty "binary countTrailingZeros" prop_ctzI+    ,testProperty "binary countTrailingZeros 0" (prop_ctzI (0::Int24))+    ,testProperty "bit/testBit" (prop_bit_ident (0::Int24))+    ,testProperty "popCount"    (prop_popCount (0::Int24) (0::Int))+    ]+  ,testGroup "Storable instance" [+    testProperty  "sizeOf Int24" prop_sizeOfI+    ,testProperty "aligntment" prop_alignI+    ]+  ]+ ]+
+ test/cert/ca-key.pem view
@@ -0,0 +1,27 @@+-----BEGIN RSA PRIVATE KEY-----+MIIEpAIBAAKCAQEAro5f0Xvee3jDWdcbfAUriec9Hle2gwGH1gWhkVJvt8e6WfSi+LJEwEQJozgj3Mo8LNcd6J1/CwD7njNXE7IoGV9mqaC2b15EwzSkVFGz7M9EFH3rK+PsipFIlevgCNpIvjHPIaGXJ6g5iVm4MxnG1k5TjNrJFHV7MeYi/aJRaLQ1ZStMRS+U8e8b59XOzJ9jJBYE+p+KWWOzRMNkIUJEM1gOPSUrWChwD01LzMeyInpEkH305Or+DTF4KfUXqWD9xMk1/l3Qk0yMWi6nEjNb3oI6yk3VzXKv6UAuy5XlEYF7ldLKezCb+4sBXPzVXMu7TCHnQR7R4X/3pIQSIaezDvNil4QIDAQABAoIBAQCNIoasvQe1M35X+3InXa+K5HKOZLfhe0lT/IgxxkILNyIqPAzJA8J85kYYl2K/uTCQXNpM41L+FaxcT+EyCm1C6ux0p18zKHSFh5+VaW7krpqX4H5uMxglLbTPqyi4X63jQiikm5+4q9bhjA+5YGuZfDnOVdqyQgzC5tsbh5mUGUHaqREdecoWPkE5etId+zWOgq2yVTYgJaTYga1+sS9rtlHQTdgI5ZuEQe11X8JT40ghApo5glXXZnSPWeSA4hNJIKKTBllxrwBG0ZYI+BVf/pSiGciEz+fYrzv9JmPTjWEWutyr2AV5OMMnv1HTY5pkFFmylQTU8AHjFfUGD+Vlf7xmpFAoGBAOb0FZqBs6HWkU4FnWKe+48sO1bMEsAu3MO6Nk+o3eTd47J+bSXe+17UyGDSzGdnH1MxVeHmEqmfiXwkP9LEVr5ywbEqgzxFyRpXOXW+DxWs2boCJoGdW+FDdzjcJxigub/auSJasynowOjpYWLvWhlutVlhXC0XOhTejPUTh/xGKLAoGBAMF8+iuRLnIGIJ9anYo4RsKp26g/wW9JcwZS1HOeKH0sqmeFGwZDoDT2Dzq844tWSMfF0+eFoGWYZkvrtFogWGPjTLDWbagErDkSP6Y9qZkQFv+68nT8/G4k322ec6jx9H0/Z7+aWhlvGzPSpOnZc6XSu40MhMlCbCjPySr4To6hYLDAoGAZVReTiXt/Gm54vOPs/9w++8Y6WsC60Vs+PRnsTlMW2B2Kk3vow57cIYHTIPwbsXN9qBEwBJDyexXVAJLhlvie+zi6RtMSNVWhAE+YxFIZKDdoZ7Yd0uyIHSLUIU3GhUaqlR6udn1lcOrMAWFVvURIO+tz4b1XxejU8OccDUL+fO8DUCgYB+oM6ZiK6dy4kfH58NkaBIf9jBo7HEY/ZBJ6MK+GchPPktFNzR5bJU1vCypWpaB5dMPzgTyDhPLM+Xr1C+sY+YUUQutU7UAuSslG7r8+FuLiyPIz+ItwVR5InhSQEzAV7cFYH/6lV2fQ4n1RUw36/eMJMFnRU70awEwT6PVX+UXONVwKBgQCgVuQEukqt9NB8Hjte9w4MhAR22ML9XUvlDbQM2LL/eKj166SxXZqL+dPaV2pcBvET1NT4UMnSZTTS4ZqsTuuE6B9Dm9lWUqMPbBDtBKykOUWSTY88rRXSW+X0HdhQ/ycxHGN8Iv/wVZKo1ZSgEcEUM4jGvWclMgsnkWuaLBZPF/dA==+-----END RSA PRIVATE KEY-----
+ test/cert/ca.pem view
@@ -0,0 +1,21 @@+-----BEGIN CERTIFICATE-----+MIIDfzCCAmegAwIBAgIJAJkP4Ih73MLQMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV+BAYTAkNOMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX+aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMMBldpbnRlcjAeFw0xNzA3MjUxMjU3NDRa+Fw0yNzA2MDMxMjU3NDRaMFYxCzAJBgNVBAYTAkNOMRMwEQYDVQQIDApTb21lLVN0+YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMM+BldpbnRlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK6OX9F73nt4+w1nXG3wFK4nnPR5XtoMBh9YFoZFSb7fHuln0oiyRMBECaM4I9zKPCzXHeidfwsA++54zVxOyKBlfZqmgtm9eRMM0pFRRs+zPRBR96yj7IqRSJXr4AjaSL4xzyGhlyeoOY+lZuDMZxtZOU4zayRR1ezHmIv2iUWi0NWUrTEUlPHvG+fVzsyfYyQWBPqfilljs0T+DZCFCRDNYDj0lK1gocA9NS8zHsiJ6RJB99OTqw0xeCn1F6lg/cTJNf5d0JNMjFou+pxIzW96COspN1c1yr+lALsuV5RGBe5XSynswm+LAVz81VzLu0wh50Ee0eF/96SEE+iGnsw7zYpeECAwEAAaNQME4wHQYDVR0OBBYEFCj3eNkh8tyrzQMsEKirVA1ilVZA+MB8GA1UdIwQYMBaAFCj3eNkh8tyrzQMsEKirVA1ilVZAMAwGA1UdEwQFMAMBAf8w+DQYJKoZIhvcNAQELBQADggEBAFUf6Q6Og8PKYlGFLq177k+DIBJKMXqDUIWuZq/Z+o11vks/4uE9LRXkicPJUbjK7Iv6mw5gHwYSxAkrJaeY6wQpiV8PoSOD1AIm448da+4SLLJMnB4vPPqrnDhoHNNOWonsZYyV6avD97+kTxM6WgJYhdwM4L1mxGGGT37nuf+JtcZHLnI3PrHj3M89xwk4BFRXnb6+X/uWZxeF0AFCWZgMtzB+iMMz0VnBmBst8RI+Xs+gYzBXN1Mq1KMcSP5r+BGE1GAM46Q5EEI29M/5Fw/38MoZlMvg4K+rdqg7GAKF+fM3q9cMZ7Uv924KcQmF5ZKoZjFjp/PfaC8WZplF6yH+y3gA=+-----END CERTIFICATE-----
+ test/cert/server-cert.pem view
@@ -0,0 +1,20 @@+-----BEGIN CERTIFICATE-----+MIIDQTCCAimgAwIBAgIBATANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjET+MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ+dHkgTHRkMQ8wDQYDVQQDDAZXaW50ZXIwHhcNMTcwNzI1MTI1ODExWhcNMjcwNjAz+MTI1ODExWjBWMQswCQYDVQQGEwJDTjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8G+A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDDAZXaW50ZXIw+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCD3Wlrhbz++Z360JuvsXD+M/CMquiGJU9XSA35g5lw7nIEsNYKzOW3dGuTzTLo/ZCw006H7eLVIZn0AZVSBSnk+teEvOHUdn56E3XVvCGBxBdbTbVrT+2hDClVg230102SYLqNwwH1fOCGVnq74sHSA+86FRLlt+uFuZCpflaXsZ6lz/dNWAP4Lwu2bA05YJAn3mxEkrlxxbsLL4X+MKpUMg+WRed+eykaFTY8G+pXmJZPLYblv5Vy+Jm5sbBuIqUElFkfHtHTpdCvahe2hcOmDcG+eKmoSav2kolFb1xov7tOXCC9DdhfuNPLE0KGAWBLu8nMDmk7apOI33U6+4OCS8Xn+AgMBAAGjGjAYMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBCwUA+A4IBAQBOKHB1StdKjQzk9cDFroR8jvbTb0PTANQYFsyAtN/VXcRLK9GxkW8Hxn/o+SO+gTStOUu4ZaS6EymJ/z0z1oHDTCifoPo3R9o3SCUH7XDM3PV3ulgG59c2tfzRw+dpK+ttfCe1e228YKfP3WI1hNnMjVnijKCJMROumQiY4CQhtUDdaAdK5jF2yvtThb+kyHuimeIoyBESBmPuGnkFtcwzxXW43Qt9Y2uJg7WxyEgoNfXL73Enx++Hv6UJSPM+sUPItS8M5wFoNJw4hpjPvXxQLrVnWd2Qs8p3LmohBpogg9C7GTzTrsM3wySxRTEA+rrbjCtYnbrs4+HD9mlbzKi9mrcXi+-----END CERTIFICATE-----
+ test/cert/server-key.pem view
@@ -0,0 +1,27 @@+-----BEGIN RSA PRIVATE KEY-----+MIIEogIBAAKCAQEAwg91pa4W8/vmd+tCbr7FwzPwjKrohiVPV0gN+YOZcO5yBLDW+Cszlt3Rrk80y6P2QsNNOh+3i1SGZ9AGVUgUp5LXhLzh1HZ+ehN11bwhgcQXW021a+0/toQwpVYNt9NdNkmC6jcMB9XzghlZ6u+LB0gPOhUS5bfrhbmQqX5Wl7Gepc/3TV+gD+C8LtmwNOWCQJ95sRJK5ccW7Cy+F/jCqVDIFkXnfnspGhU2PBvqV5iWTy2G5b++VcviZubGwbiKlBJRZHx7R06XQr2oXtoXDpg3BnipqEmr9pKJRW9caL+7TlwgvQ3Y+X7jTyxNChgFgS7vJzA5pO2qTiN91OvuDgkvF5wIDAQABAoIBAFG0gpscPivBrlpl+IhZQmiFC2A/R0Y7RXKNqAgBA6TTEIBtbfPMVK87e5IBZUAsK34WjohfXD78eo5w5+om3jIK1b6pCgG6c6Ulqsh0oVY82SYM2p6CkCW/aF/kaGgyRLebodQNEzKlYR4woE+wrSQTq0QZqYwd3NWGbLI5AVCMQNKjk/ogHOGAxwNGAzB3KHG55zQL68iu77vSJFa+gf9MtSgaqxosWedtdRWVo9N2jm3BhrebK85J5bZQUp6xHvHSgbW/PGWQMiJUzuzo+wzmBhkE4RM5hgBtBBUs6lP/trxzl1eKEkDSQdsxpZ5bIz0dhe3ZUqHM/apTVoD1n+OBYTfWkCgYEA8Ue08d2C44wJTqyY1a+Tf0kSrNFEYjqWTKe19nzlQ7mFoUP6ORIw+z6pLvliFSFFxQrB2uAzgJGIYdUY62XCV7Cm7gIfQxJEv2jUJ8ZNFTyZGKvBVxQu6+98CDkmsK5Zgjd/fhZb/7c6a9tdNm6C0Z/tcvi/CqhCiK5UmBYTXOeuUCgYEAzeZH+buv65edEsxesHxZjSFIekEnvUUQw8JpRn/Cr9nzOem9quBwp85PNAoEPkBiDeq6C+2xE6wFO0C17cw5oPahkTg0C+PbKmNA3HWZLYXjAEke+bXponEGiBKtrcuoXPiRVi+dLXVQyZ09sSd9QFVz0zb+yhnxmB8ckz6m3Qn1NsCgYBiMBo0qz5Ot3g6KgbwPsk5+bVVKOscnakwr2bw1GNJ74w28eNtlSj/O4rB8P63Npkb/KqzFbYfxhnIJl5DvV9/L+AZiqT5rnw2XD2P2474OvGBZJ9xAQZhuqIw/oD+OZV3Znpdp1+9CqWdquGd+w8Fm5+2Xwh6Mibi5wqfuVF2A20+QKBgCXlQjR6Hj1+KTjFHJrEJhXDd3ibAv70DAXcgTVs+uFmvctk59GxaUqZQB6V0V4bv3BMSV2c2bpfDUBnfpcYibr/aSasYmWsFnG1sM8qa+qlP7hnvNm8z3lkUA1vUqPwHdausSEoLkjJHFXDWmzmOvkTmMLdi2AROT4pOu81j1+MfeNAoGAIbS1Gngub9JDeoyWPRPNkZaNXIaPdkXOXmwJvigbnWstgbHsgu24HfJc+LCkS8MIYWVSbceDZflkSaJ9ZF0dGEJPPNdsfPi3x2iWTYHp8as9+8JnSsG4C8fvA+gQZLrF0JxP7B4ZmHYNawtQBVnrcKldwCuotP16V7lH+we3xuezQ=+-----END RSA PRIVATE KEY-----
+ test/cert/server-req.pem view
@@ -0,0 +1,16 @@+-----BEGIN CERTIFICATE REQUEST-----+MIICmzCCAYMCAQAwVjELMAkGA1UEBhMCQ04xEzARBgNVBAgMClNvbWUtU3RhdGUx+ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGV2lu+dGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwg91pa4W8/vmd+tC+br7FwzPwjKrohiVPV0gN+YOZcO5yBLDWCszlt3Rrk80y6P2QsNNOh+3i1SGZ9AGV+UgUp5LXhLzh1HZ+ehN11bwhgcQXW021a0/toQwpVYNt9NdNkmC6jcMB9XzghlZ6u++LB0gPOhUS5bfrhbmQqX5Wl7Gepc/3TVgD+C8LtmwNOWCQJ95sRJK5ccW7Cy+F/j+CqVDIFkXnfnspGhU2PBvqV5iWTy2G5b+VcviZubGwbiKlBJRZHx7R06XQr2oXtoX+Dpg3BnipqEmr9pKJRW9caL+7TlwgvQ3YX7jTyxNChgFgS7vJzA5pO2qTiN91OvuD+gkvF5wIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAIjdOfU/dtQcP/Da1IIXlLji+wFCHk5/jlC+oxSIXKtF+3ZBrCx3R/pm7V9ERbeJWXswlhd+8Rkeyde+L3PnDly77+F2oKa1jKcp3lituP1V7tVM8WvScZbLC3RAKFioapN9+Jbwhs8DVtKryNiAtndjFl+jRG3+7xS5rOijgVTStzqvYfRqcUJvvgdT62EV2oSq59ZjNmYkvj8ZAUuI8feKDNm+TdTdGnaC0Br83XNiTKtsSLKk9p0WudzZkiCaeR07hOA1AoJ30DSnsQE+BG/5f/nn+1RbEybGDaFPTULYGXsoZ4TTcr5sxgfXmhomBn/iF/Ns5LEvNosKqwOOPPM4P0eI=+-----END CERTIFICATE REQUEST-----
+ test/json-data/buffer-builder.json view
@@ -0,0 +1,4322 @@+[+  {+    "_id": "54727a90e43524efe8abfdac",+    "index": 0,+    "guid": "aaa926e8-8359-4afe-adb0-dca0401de765",+    "isActive": true,+    "balance": "$1,114.73",+    "picture": "http://placehold.it/32x32",+    "age": 20,+    "eyeColor": "green",+    "name": "Dillon Valenzuela",+    "gender": "male",+    "company": "GEOFORM",+    "email": "dillonvalenzuela@geoform.com",+    "phone": "+1 (817) 536-3796",+    "address": "309 Desmond Court, Zarephath, Montana, 6156",+    "about": "Dolore laboris excepteur sunt velit velit nostrud non esse qui laboris nostrud Lorem. Amet anim occaecat et ipsum. Ad proident nostrud elit adipisicing anim labore consectetur ut amet elit. Tempor aliqua in ea eiusmod elit Lorem cillum est laboris. Nisi Lorem amet amet Lorem. Nostrud sunt incididunt magna nostrud amet enim. Laboris ad et fugiat dolor ad proident aliquip nisi do ea eiusmod enim proident.\r\n",+    "registered": "2014-08-17T07:29:03 +07:00",+    "latitude": -17.423462,+    "longitude": 121.069662,+    "tags": [+      "sunt",+      "ex",+      "irure",+      "cillum",+      "velit",+      "duis",+      "sit"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Joyce Jordan"+      },+      {+        "id": 1,+        "name": "Ophelia Rosales"+      },+      {+        "id": 2,+        "name": "Florine Stark"+      }+    ],+    "greeting": "Hello, Dillon Valenzuela! You have 9 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90f520a07ff2498a69",+    "index": 1,+    "guid": "8f78cc18-a7ef-498b-9adf-60f008a48c02",+    "isActive": false,+    "balance": "$1,324.52",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "blue",+    "name": "Donovan Weiss",+    "gender": "male",+    "company": "TELPOD",+    "email": "donovanweiss@telpod.com",+    "phone": "+1 (962) 417-2408",+    "address": "511 Grant Avenue, Westmoreland, Hawaii, 5092",+    "about": "Laborum excepteur exercitation sint veniam dolor. Dolor aliqua esse do aliqua adipisicing. Ea magna minim veniam tempor ipsum. Incididunt anim reprehenderit occaecat proident eiusmod anim Lorem aliquip dolore incididunt. Consequat occaecat qui minim commodo est velit ex.\r\n",+    "registered": "2014-09-30T23:49:41 +07:00",+    "latitude": -18.034963,+    "longitude": 70.821705,+    "tags": [+      "cupidatat",+      "excepteur",+      "id",+      "consectetur",+      "ea",+      "enim",+      "et"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Cummings Irwin"+      },+      {+        "id": 1,+        "name": "Conley Lester"+      },+      {+        "id": 2,+        "name": "Katy Holt"+      }+    ],+    "greeting": "Hello, Donovan Weiss! You have 2 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90fbb3f49ea6d40dde",+    "index": 2,+    "guid": "69a4c6d7-6189-4a90-ae00-7b64ab1d5a2d",+    "isActive": false,+    "balance": "$2,739.87",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "brown",+    "name": "Renee Calderon",+    "gender": "female",+    "company": "TALKOLA",+    "email": "reneecalderon@talkola.com",+    "phone": "+1 (910) 523-3382",+    "address": "323 Montauk Avenue, Greenwich, South Dakota, 8034",+    "about": "Reprehenderit deserunt et do proident Lorem Lorem dolor labore ullamco eu nulla laborum voluptate. Consectetur sint magna enim commodo dolore ullamco in. Nulla id proident esse veniam proident esse velit exercitation do. Qui nulla magna anim Lorem dolor culpa id. Nostrud cupidatat officia culpa sit irure voluptate exercitation voluptate nostrud elit. Duis occaecat velit fugiat exercitation anim aute laborum irure.\r\n",+    "registered": "2014-09-11T20:48:20 +07:00",+    "latitude": 15.654081,+    "longitude": 84.156609,+    "tags": [+      "dolor",+      "et",+      "in",+      "veniam",+      "non",+      "est",+      "enim"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Gilda Murray"+      },+      {+        "id": 1,+        "name": "Marguerite West"+      },+      {+        "id": 2,+        "name": "Chrystal Rojas"+      }+    ],+    "greeting": "Hello, Renee Calderon! You have 1 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90c5ea2a48502a0640",+    "index": 3,+    "guid": "689a64d7-16b0-41dc-947d-035b40a29ed4",+    "isActive": false,+    "balance": "$3,805.39",+    "picture": "http://placehold.it/32x32",+    "age": 32,+    "eyeColor": "blue",+    "name": "Aguirre Garrett",+    "gender": "male",+    "company": "ZOSIS",+    "email": "aguirregarrett@zosis.com",+    "phone": "+1 (811) 471-3145",+    "address": "198 Baycliff Terrace, Clarence, District Of Columbia, 1528",+    "about": "Deserunt minim aliquip magna ut fugiat quis. Quis consequat culpa reprehenderit minim do eiusmod adipisicing nostrud aute. Lorem nostrud laborum quis dolore tempor tempor magna aute eu pariatur dolor est. Reprehenderit ex consectetur adipisicing Lorem nostrud fugiat aute non quis anim laborum aute proident amet. Sunt consectetur eu ut eu mollit ipsum.\r\n",+    "registered": "2014-02-14T04:27:27 +08:00",+    "latitude": 25.922024,+    "longitude": 107.428199,+    "tags": [+      "esse",+      "officia",+      "commodo",+      "esse",+      "cupidatat",+      "amet",+      "ad"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Penelope Humphrey"+      },+      {+        "id": 1,+        "name": "Church Byers"+      },+      {+        "id": 2,+        "name": "Hazel Stafford"+      }+    ],+    "greeting": "Hello, Aguirre Garrett! You have 4 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a9096bcf2d2f4b4aeff",+    "index": 4,+    "guid": "77392422-81ad-48c8-9cfc-37d142a814d5",+    "isActive": false,+    "balance": "$1,956.06",+    "picture": "http://placehold.it/32x32",+    "age": 26,+    "eyeColor": "brown",+    "name": "Griffin Mclaughlin",+    "gender": "male",+    "company": "COMTOUR",+    "email": "griffinmclaughlin@comtour.com",+    "phone": "+1 (950) 494-2956",+    "address": "549 Robert Street, Libertytown, North Carolina, 4377",+    "about": "Exercitation culpa ad id deserunt sit ullamco anim anim ad aute officia ut tempor. Ullamco dolor pariatur enim exercitation commodo consectetur fugiat velit nulla mollit pariatur occaecat. Amet voluptate qui labore mollit ipsum consequat. Esse pariatur proident ad pariatur aliquip labore quis voluptate quis ut culpa tempor. Reprehenderit sint id officia deserunt quis laboris. Velit ipsum dolore anim consectetur.\r\n",+    "registered": "2014-06-23T04:48:12 +07:00",+    "latitude": 8.808284,+    "longitude": 20.539814,+    "tags": [+      "consequat",+      "proident",+      "eiusmod",+      "dolore",+      "in",+      "laborum",+      "non"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Hinton Santiago"+      },+      {+        "id": 1,+        "name": "Talley Dyer"+      },+      {+        "id": 2,+        "name": "Karen Logan"+      }+    ],+    "greeting": "Hello, Griffin Mclaughlin! You have 3 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a9010e5c5ac55919561",+    "index": 5,+    "guid": "7e6fca4d-0329-47ab-b3e7-f4d6a6ee4dd2",+    "isActive": true,+    "balance": "$3,767.46",+    "picture": "http://placehold.it/32x32",+    "age": 36,+    "eyeColor": "brown",+    "name": "Rachel Mcclure",+    "gender": "female",+    "company": "ESCENTA",+    "email": "rachelmcclure@escenta.com",+    "phone": "+1 (857) 518-3454",+    "address": "901 Harwood Place, Rossmore, Tennessee, 3213",+    "about": "Nisi enim deserunt ut ex mollit fugiat. Magna nostrud culpa irure nulla mollit nisi. Sit ea incididunt amet culpa veniam voluptate Lorem sunt dolore amet. Exercitation tempor eiusmod exercitation officia dolor. Ut ea sint veniam cupidatat et. Sunt nostrud ad ipsum non elit elit esse ut dolor. Et officia et minim ipsum amet sint eu ut nostrud adipisicing cillum ullamco.\r\n",+    "registered": "2014-05-29T20:42:11 +07:00",+    "latitude": 8.132878,+    "longitude": -99.198755,+    "tags": [+      "est",+      "Lorem",+      "ullamco",+      "nisi",+      "reprehenderit",+      "nisi",+      "cupidatat"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Michael Martin"+      },+      {+        "id": 1,+        "name": "Gayle Heath"+      },+      {+        "id": 2,+        "name": "Slater Bender"+      }+    ],+    "greeting": "Hello, Rachel Mcclure! You have 2 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90a76a5ba627b180c9",+    "index": 6,+    "guid": "fbf59485-142c-4eb6-a98e-8952cbb19942",+    "isActive": true,+    "balance": "$2,139.12",+    "picture": "http://placehold.it/32x32",+    "age": 28,+    "eyeColor": "blue",+    "name": "Megan Morrow",+    "gender": "female",+    "company": "PETICULAR",+    "email": "meganmorrow@peticular.com",+    "phone": "+1 (825) 572-2854",+    "address": "151 Jardine Place, Boonville, Idaho, 160",+    "about": "Magna reprehenderit aliqua quis eiusmod eu minim ut. Consectetur non veniam est et aliqua mollit. Aliqua eiusmod sit fugiat qui quis nisi mollit officia do. Enim quis quis occaecat ullamco anim reprehenderit exercitation. Ad id id laborum ipsum ipsum cillum ipsum occaecat irure. Commodo voluptate ullamco excepteur ea laboris adipisicing veniam cillum commodo velit anim. Occaecat magna laborum non ex anim consequat dolor cillum excepteur velit duis commodo officia veniam.\r\n",+    "registered": "2014-04-16T08:56:52 +07:00",+    "latitude": 57.771446,+    "longitude": -146.885322,+    "tags": [+      "veniam",+      "officia",+      "magna",+      "ipsum",+      "nulla",+      "ea",+      "mollit"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Marina Wise"+      },+      {+        "id": 1,+        "name": "Ann Mercado"+      },+      {+        "id": 2,+        "name": "Glenn Duran"+      }+    ],+    "greeting": "Hello, Megan Morrow! You have 7 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90776f7328f4df750f",+    "index": 7,+    "guid": "ef99cc91-061c-49c5-9901-3ac22a75bc92",+    "isActive": true,+    "balance": "$3,161.69",+    "picture": "http://placehold.it/32x32",+    "age": 37,+    "eyeColor": "blue",+    "name": "Lawson Kirby",+    "gender": "male",+    "company": "PLASMOSIS",+    "email": "lawsonkirby@plasmosis.com",+    "phone": "+1 (853) 583-2577",+    "address": "122 Linden Boulevard, Edneyville, Palau, 6050",+    "about": "Elit ullamco reprehenderit eiusmod in duis minim exercitation incididunt reprehenderit eiusmod nulla. Cupidatat ea anim incididunt esse ea eu esse laboris velit. Culpa sunt exercitation officia amet voluptate enim duis ipsum ex anim quis nisi. Dolor officia irure do veniam do amet ullamco eu.\r\n",+    "registered": "2014-08-13T02:14:13 +07:00",+    "latitude": -16.166232,+    "longitude": 12.254111,+    "tags": [+      "et",+      "aliqua",+      "aute",+      "voluptate",+      "officia",+      "est",+      "quis"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Marquita Hutchinson"+      },+      {+        "id": 1,+        "name": "Karla Conner"+      },+      {+        "id": 2,+        "name": "Mattie Page"+      }+    ],+    "greeting": "Hello, Lawson Kirby! You have 3 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90b8e9fff0ed297a59",+    "index": 8,+    "guid": "9bb8d813-704c-4714-929f-1321576a2701",+    "isActive": false,+    "balance": "$1,275.37",+    "picture": "http://placehold.it/32x32",+    "age": 23,+    "eyeColor": "brown",+    "name": "Pat Medina",+    "gender": "female",+    "company": "PLEXIA",+    "email": "patmedina@plexia.com",+    "phone": "+1 (933) 557-3028",+    "address": "623 Sunnyside Court, Edinburg, Minnesota, 2620",+    "about": "Est aliqua sint adipisicing labore magna sunt laboris non eu. Aute deserunt commodo Lorem amet sunt amet qui qui incididunt anim Lorem culpa. Ea exercitation officia dolor aute incididunt ea enim. Nulla aliqua ut ullamco sunt velit cillum esse minim incididunt ut mollit aute. Fugiat eiusmod anim laborum duis aliquip aute reprehenderit qui dolor officia amet labore id. Enim officia reprehenderit incididunt sit. Nisi ullamco nisi adipisicing esse eiusmod dolore veniam cupidatat consequat sunt.\r\n",+    "registered": "2014-10-22T20:29:14 +07:00",+    "latitude": -9.032987,+    "longitude": 71.98971,+    "tags": [+      "laborum",+      "dolore",+      "aliqua",+      "tempor",+      "eu",+      "elit",+      "voluptate"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Elnora Moses"+      },+      {+        "id": 1,+        "name": "Alexandra Carter"+      },+      {+        "id": 2,+        "name": "Beth Pacheco"+      }+    ],+    "greeting": "Hello, Pat Medina! You have 5 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a908c17a619571cfd39",+    "index": 9,+    "guid": "0a5de094-eadc-4120-8941-964f27fbc898",+    "isActive": true,+    "balance": "$1,939.34",+    "picture": "http://placehold.it/32x32",+    "age": 35,+    "eyeColor": "brown",+    "name": "Gibbs Butler",+    "gender": "male",+    "company": "OPTIQUE",+    "email": "gibbsbutler@optique.com",+    "phone": "+1 (956) 574-3434",+    "address": "552 Columbia Street, Richmond, Illinois, 903",+    "about": "Laboris eu ut magna exercitation non laboris sint. Mollit velit est exercitation enim exercitation reprehenderit culpa eiusmod laboris fugiat veniam adipisicing. Voluptate enim id do eu officia duis in incididunt. Esse do laboris pariatur cupidatat elit.\r\n",+    "registered": "2014-02-24T15:46:23 +08:00",+    "latitude": -68.874573,+    "longitude": -6.876165,+    "tags": [+      "excepteur",+      "deserunt",+      "ea",+      "labore",+      "aliqua",+      "deserunt",+      "labore"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Chen Langley"+      },+      {+        "id": 1,+        "name": "Latonya Vaughan"+      },+      {+        "id": 2,+        "name": "Simone Sutton"+      }+    ],+    "greeting": "Hello, Gibbs Butler! You have 2 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a9049447027a378812c",+    "index": 10,+    "guid": "406ae437-820d-4e0f-b8dc-1da0ddcc561c",+    "isActive": false,+    "balance": "$1,348.37",+    "picture": "http://placehold.it/32x32",+    "age": 39,+    "eyeColor": "brown",+    "name": "Bond Peck",+    "gender": "male",+    "company": "DANCERITY",+    "email": "bondpeck@dancerity.com",+    "phone": "+1 (918) 554-2856",+    "address": "361 Cortelyou Road, Hollins, Missouri, 131",+    "about": "Nisi ut ea ut deserunt. Consequat pariatur dolor consequat sunt. Ullamco aute proident excepteur fugiat id consequat eu nisi occaecat.\r\n",+    "registered": "2014-05-15T02:12:14 +07:00",+    "latitude": -79.266187,+    "longitude": 92.89454,+    "tags": [+      "ex",+      "est",+      "sit",+      "irure",+      "qui",+      "veniam",+      "exercitation"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Nettie Pope"+      },+      {+        "id": 1,+        "name": "Alyssa Hensley"+      },+      {+        "id": 2,+        "name": "Puckett Kinney"+      }+    ],+    "greeting": "Hello, Bond Peck! You have 7 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a9062a82eff9506c4d7",+    "index": 11,+    "guid": "b7400b79-2b71-46cd-9260-13e0767b437e",+    "isActive": true,+    "balance": "$1,757.66",+    "picture": "http://placehold.it/32x32",+    "age": 20,+    "eyeColor": "blue",+    "name": "Garrison Warner",+    "gender": "male",+    "company": "NAMEBOX",+    "email": "garrisonwarner@namebox.com",+    "phone": "+1 (874) 417-2183",+    "address": "927 Knapp Street, Shaft, Connecticut, 2188",+    "about": "Sint commodo ipsum commodo id magna labore in. Pariatur nostrud reprehenderit adipisicing amet enim ut quis laboris culpa exercitation deserunt cillum. Adipisicing excepteur sunt do labore anim exercitation non excepteur. Minim consectetur sit dolore occaecat et aliquip aliquip excepteur aliquip ut do eiusmod ea nulla. Nostrud sunt dolore ea sunt est enim occaecat culpa minim. Sit elit mollit mollit aliquip eu ex. Tempor nulla voluptate dolore ex.\r\n",+    "registered": "2014-06-18T03:58:19 +07:00",+    "latitude": -87.629414,+    "longitude": 96.653639,+    "tags": [+      "eu",+      "deserunt",+      "dolore",+      "nisi",+      "culpa",+      "ullamco",+      "ipsum"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Gutierrez Sears"+      },+      {+        "id": 1,+        "name": "Holly Jacobson"+      },+      {+        "id": 2,+        "name": "Henry Delgado"+      }+    ],+    "greeting": "Hello, Garrison Warner! You have 4 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a904638f48ca7f9e85e",+    "index": 12,+    "guid": "4cd59615-46b7-4733-a439-dc59c0ca0118",+    "isActive": true,+    "balance": "$3,897.06",+    "picture": "http://placehold.it/32x32",+    "age": 24,+    "eyeColor": "blue",+    "name": "Consuelo Bray",+    "gender": "female",+    "company": "COMTEST",+    "email": "consuelobray@comtest.com",+    "phone": "+1 (945) 432-2620",+    "address": "433 Clinton Street, Clarktown, Maine, 6916",+    "about": "Do occaecat consectetur tempor Lorem ullamco commodo exercitation veniam reprehenderit nulla officia. Nisi irure sunt cupidatat amet et excepteur quis et do. Et commodo nulla occaecat do sint quis mollit reprehenderit do laboris magna. Dolore ea sit aute esse consequat fugiat Lorem occaecat adipisicing adipisicing qui aute elit. Amet veniam anim ipsum aute officia. Fugiat nisi magna anim pariatur minim magna exercitation duis officia.\r\n",+    "registered": "2014-03-19T07:39:44 +07:00",+    "latitude": 7.760448,+    "longitude": -92.399314,+    "tags": [+      "irure",+      "veniam",+      "ex",+      "ullamco",+      "anim",+      "do",+      "enim"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Ellen Bullock"+      },+      {+        "id": 1,+        "name": "Davis Vaughn"+      },+      {+        "id": 2,+        "name": "Robert Mendoza"+      }+    ],+    "greeting": "Hello, Consuelo Bray! You have 8 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90fd85a45d33d54cf7",+    "index": 13,+    "guid": "53868eb7-df5c-445d-ad62-6124db081b6c",+    "isActive": false,+    "balance": "$2,988.04",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "green",+    "name": "Clark Skinner",+    "gender": "male",+    "company": "OVOLO",+    "email": "clarkskinner@ovolo.com",+    "phone": "+1 (834) 587-2391",+    "address": "967 Dewey Place, Gibsonia, Puerto Rico, 6398",+    "about": "Duis irure exercitation ullamco amet aliquip minim sit consequat officia laborum id ad. Lorem duis velit consequat non irure nulla elit elit velit dolor ullamco qui fugiat. Quis ad velit ea consectetur veniam Lorem incididunt quis magna eiusmod. Et nostrud irure tempor nostrud esse.\r\n",+    "registered": "2014-10-11T06:48:59 +07:00",+    "latitude": -62.633073,+    "longitude": -121.03338,+    "tags": [+      "ut",+      "deserunt",+      "adipisicing",+      "enim",+      "amet",+      "proident",+      "officia"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Francine Petersen"+      },+      {+        "id": 1,+        "name": "Lena Robles"+      },+      {+        "id": 2,+        "name": "Mcintyre Gardner"+      }+    ],+    "greeting": "Hello, Clark Skinner! You have 6 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a908789850c55818269",+    "index": 14,+    "guid": "84cc7d0b-0544-40f8-900a-825429b0ee87",+    "isActive": true,+    "balance": "$3,012.07",+    "picture": "http://placehold.it/32x32",+    "age": 32,+    "eyeColor": "blue",+    "name": "Katie Allen",+    "gender": "female",+    "company": "SYBIXTEX",+    "email": "katieallen@sybixtex.com",+    "phone": "+1 (959) 504-2563",+    "address": "543 Heath Place, Bartonsville, New Mexico, 4882",+    "about": "Nisi ullamco anim in culpa in non nostrud ex aliqua ex. Nisi occaecat exercitation sint ad magna Lorem amet anim pariatur quis. Dolore consequat quis dolor ea. Aliquip sunt ex cillum tempor fugiat laboris ipsum mollit aliqua reprehenderit nulla fugiat exercitation ad.\r\n",+    "registered": "2014-03-17T05:45:50 +07:00",+    "latitude": -79.18988,+    "longitude": -95.023826,+    "tags": [+      "commodo",+      "incididunt",+      "voluptate",+      "sit",+      "mollit",+      "veniam",+      "et"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Hampton Jimenez"+      },+      {+        "id": 1,+        "name": "Lara Cline"+      },+      {+        "id": 2,+        "name": "Jennings Cantu"+      }+    ],+    "greeting": "Hello, Katie Allen! You have 3 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90787015f61850162f",+    "index": 15,+    "guid": "d848ac32-1d24-471a-ad7e-d272f52cb5fc",+    "isActive": true,+    "balance": "$1,416.33",+    "picture": "http://placehold.it/32x32",+    "age": 38,+    "eyeColor": "brown",+    "name": "Pratt Watson",+    "gender": "male",+    "company": "HARMONEY",+    "email": "prattwatson@harmoney.com",+    "phone": "+1 (905) 557-3197",+    "address": "867 Campus Road, Lindisfarne, Northern Mariana Islands, 8349",+    "about": "Nisi mollit eu reprehenderit qui ut eu cillum cupidatat do. Et ex qui minim proident. Quis aliquip aliquip exercitation exercitation dolor aute nostrud fugiat ea. Id ullamco occaecat reprehenderit mollit occaecat ea ipsum cupidatat ea consequat fugiat.\r\n",+    "registered": "2014-11-15T05:07:03 +08:00",+    "latitude": -66.117872,+    "longitude": 52.197654,+    "tags": [+      "ullamco",+      "sunt",+      "ea",+      "veniam",+      "elit",+      "sint",+      "id"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Dale Ray"+      },+      {+        "id": 1,+        "name": "Beryl Hayes"+      },+      {+        "id": 2,+        "name": "Millie Good"+      }+    ],+    "greeting": "Hello, Pratt Watson! You have 2 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90c4106283f0c1eed9",+    "index": 16,+    "guid": "6839b0af-5c69-45e2-b83b-381ff05034e6",+    "isActive": false,+    "balance": "$2,720.67",+    "picture": "http://placehold.it/32x32",+    "age": 31,+    "eyeColor": "blue",+    "name": "Shari Mendez",+    "gender": "female",+    "company": "INDEXIA",+    "email": "sharimendez@indexia.com",+    "phone": "+1 (895) 589-3754",+    "address": "533 Conduit Boulevard, Forestburg, Mississippi, 6873",+    "about": "Ex excepteur elit id laborum veniam dolore duis ea eiusmod minim. Consequat reprehenderit magna elit tempor voluptate esse officia minim reprehenderit consequat fugiat qui eiusmod. Et Lorem nisi voluptate tempor nulla cillum reprehenderit pariatur elit dolore occaecat laboris sunt. Anim cupidatat do veniam pariatur nostrud anim eu aliqua veniam ad cillum quis.\r\n",+    "registered": "2014-05-04T10:15:37 +07:00",+    "latitude": 31.931465,+    "longitude": 155.732674,+    "tags": [+      "enim",+      "sint",+      "est",+      "aliqua",+      "elit",+      "laboris",+      "occaecat"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Desiree Norris"+      },+      {+        "id": 1,+        "name": "Abigail Crosby"+      },+      {+        "id": 2,+        "name": "Anderson Alston"+      }+    ],+    "greeting": "Hello, Shari Mendez! You have 6 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90474ecbf0a9c34382",+    "index": 17,+    "guid": "079bb238-0556-4ede-8243-2eaadabb3050",+    "isActive": false,+    "balance": "$2,629.01",+    "picture": "http://placehold.it/32x32",+    "age": 26,+    "eyeColor": "green",+    "name": "Hancock Rowland",+    "gender": "male",+    "company": "SOFTMICRO",+    "email": "hancockrowland@softmicro.com",+    "phone": "+1 (983) 565-2302",+    "address": "168 Dooley Street, Driftwood, North Dakota, 3607",+    "about": "Eu voluptate velit incididunt ipsum amet veniam. Lorem aliquip adipisicing incididunt laborum aliqua elit consectetur aute velit voluptate ea. Mollit irure duis consequat veniam sint nostrud est dolore sunt anim laboris fugiat. Dolor officia elit esse elit dolore. Minim non est duis culpa ullamco veniam excepteur. Veniam ullamco amet ullamco esse voluptate laboris velit.\r\n",+    "registered": "2014-09-06T04:32:40 +07:00",+    "latitude": -68.853851,+    "longitude": 135.592762,+    "tags": [+      "nulla",+      "ut",+      "magna",+      "adipisicing",+      "officia",+      "nulla",+      "cillum"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Shannon Burch"+      },+      {+        "id": 1,+        "name": "Marisol Nixon"+      },+      {+        "id": 2,+        "name": "Poole Wolfe"+      }+    ],+    "greeting": "Hello, Hancock Rowland! You have 4 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90cf708eccc9032fd0",+    "index": 18,+    "guid": "8930775e-9271-400e-b662-77ee520b3369",+    "isActive": false,+    "balance": "$1,026.68",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "blue",+    "name": "Luna Rice",+    "gender": "male",+    "company": "GEEKULAR",+    "email": "lunarice@geekular.com",+    "phone": "+1 (840) 541-2996",+    "address": "417 Varick Avenue, Martell, Vermont, 2749",+    "about": "Aliqua enim ullamco do eiusmod. Ipsum incididunt minim esse veniam nisi velit. Ipsum reprehenderit velit eiusmod nisi magna dolore consectetur reprehenderit magna culpa. Commodo excepteur labore proident adipisicing in velit sit occaecat reprehenderit id.\r\n",+    "registered": "2014-10-15T05:13:55 +07:00",+    "latitude": -57.335675,+    "longitude": -173.387514,+    "tags": [+      "fugiat",+      "enim",+      "exercitation",+      "aliquip",+      "Lorem",+      "laboris",+      "deserunt"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Mclaughlin Schmidt"+      },+      {+        "id": 1,+        "name": "Munoz Key"+      },+      {+        "id": 2,+        "name": "Candace Stephenson"+      }+    ],+    "greeting": "Hello, Luna Rice! You have 2 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90a0fd17c9e4f5d33f",+    "index": 19,+    "guid": "570f0e20-085f-4c40-9e84-b555cc4e79c8",+    "isActive": true,+    "balance": "$3,333.73",+    "picture": "http://placehold.it/32x32",+    "age": 39,+    "eyeColor": "green",+    "name": "Beverly Newton",+    "gender": "female",+    "company": "ECLIPSENT",+    "email": "beverlynewton@eclipsent.com",+    "phone": "+1 (902) 595-3072",+    "address": "903 Knight Court, Gardiner, Rhode Island, 3327",+    "about": "Labore culpa tempor nisi commodo dolore exercitation est eu. Aute exercitation duis proident deserunt culpa ullamco. Irure cillum elit ea sint dolore ipsum adipisicing anim sit. Amet incididunt labore ex fugiat mollit quis reprehenderit nisi ut excepteur proident ullamco laboris. Reprehenderit voluptate aliqua labore culpa in non magna velit nostrud amet. Minim nulla ea culpa irure. Minim ea ex nisi proident ex ex quis ipsum culpa.\r\n",+    "registered": "2014-09-23T10:25:17 +07:00",+    "latitude": 23.973865,+    "longitude": -71.604537,+    "tags": [+      "ullamco",+      "anim",+      "id",+      "pariatur",+      "est",+      "cupidatat",+      "qui"+    ],+    "friends": [+      {+        "id": 0,+        "name": "James Garner"+      },+      {+        "id": 1,+        "name": "Goff Reese"+      },+      {+        "id": 2,+        "name": "Casey Bradford"+      }+    ],+    "greeting": "Hello, Beverly Newton! You have 2 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90fd0cafc2fa513aea",+    "index": 20,+    "guid": "c0e243a3-bf20-4112-8dab-0b0aed785060",+    "isActive": true,+    "balance": "$2,290.97",+    "picture": "http://placehold.it/32x32",+    "age": 28,+    "eyeColor": "blue",+    "name": "Stokes Dodson",+    "gender": "male",+    "company": "SLAMBDA",+    "email": "stokesdodson@slambda.com",+    "phone": "+1 (994) 443-2829",+    "address": "232 Kosciusko Street, Manitou, Michigan, 2638",+    "about": "Nostrud minim cillum elit reprehenderit ut do eu. Quis deserunt enim nisi do proident quis quis voluptate elit. Sit nostrud et amet nostrud pariatur exercitation cillum ullamco laborum ullamco do id. Tempor incididunt dolore consequat ut amet in reprehenderit magna anim laboris reprehenderit tempor adipisicing.\r\n",+    "registered": "2014-05-21T16:30:03 +07:00",+    "latitude": -86.112825,+    "longitude": 56.089279,+    "tags": [+      "ea",+      "dolor",+      "dolor",+      "consequat",+      "nulla",+      "cillum",+      "voluptate"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Jodi Camacho"+      },+      {+        "id": 1,+        "name": "Michele Miles"+      },+      {+        "id": 2,+        "name": "Rene Mitchell"+      }+    ],+    "greeting": "Hello, Stokes Dodson! You have 9 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a908be67242a33d9597",+    "index": 21,+    "guid": "8ad92a47-ac1d-46ad-9dc3-d1f96526bf1d",+    "isActive": true,+    "balance": "$1,134.78",+    "picture": "http://placehold.it/32x32",+    "age": 20,+    "eyeColor": "green",+    "name": "Jody Stewart",+    "gender": "female",+    "company": "EARGO",+    "email": "jodystewart@eargo.com",+    "phone": "+1 (925) 470-3426",+    "address": "271 Norwood Avenue, Sperryville, Oklahoma, 9504",+    "about": "Ut cillum ea pariatur Lorem ad veniam ex ullamco. Exercitation culpa sit occaecat aliquip eu quis magna exercitation quis reprehenderit nostrud consequat. Exercitation magna duis culpa nulla id proident. Adipisicing sunt consequat laborum consequat id dolore aute qui. Consectetur magna irure minim ut consectetur elit qui elit voluptate sint excepteur officia.\r\n",+    "registered": "2014-04-29T09:04:08 +07:00",+    "latitude": -51.736959,+    "longitude": -37.406481,+    "tags": [+      "officia",+      "ullamco",+      "velit",+      "nulla",+      "ipsum",+      "eiusmod",+      "mollit"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Jodie Browning"+      },+      {+        "id": 1,+        "name": "Collins Gamble"+      },+      {+        "id": 2,+        "name": "Emerson Mccullough"+      }+    ],+    "greeting": "Hello, Jody Stewart! You have 4 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a905956037e359d6786",+    "index": 22,+    "guid": "730467a3-9f5d-4d41-9503-09f30222dffa",+    "isActive": false,+    "balance": "$1,821.23",+    "picture": "http://placehold.it/32x32",+    "age": 24,+    "eyeColor": "brown",+    "name": "Wall Moss",+    "gender": "male",+    "company": "BOILICON",+    "email": "wallmoss@boilicon.com",+    "phone": "+1 (865) 518-2689",+    "address": "902 Fleet Street, Cornfields, West Virginia, 9088",+    "about": "Consectetur voluptate enim est elit dolor adipisicing reprehenderit ut in proident sunt. Fugiat cillum anim ullamco qui laborum sit. Dolore qui mollit ut irure proident consequat est veniam. Qui incididunt quis duis enim quis cupidatat do nostrud dolore labore consectetur laboris consectetur. Adipisicing veniam amet officia mollit incididunt non veniam ea laboris. Enim adipisicing velit in dolore proident Lorem esse et sunt.\r\n",+    "registered": "2014-01-21T18:36:59 +08:00",+    "latitude": -70.265889,+    "longitude": -148.213176,+    "tags": [+      "ea",+      "cillum",+      "ea",+      "enim",+      "aliqua",+      "nostrud",+      "do"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Margaret Chavez"+      },+      {+        "id": 1,+        "name": "Mendez Garrison"+      },+      {+        "id": 2,+        "name": "Howard Ortiz"+      }+    ],+    "greeting": "Hello, Wall Moss! You have 9 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a9062feb6c7bfa8710d",+    "index": 23,+    "guid": "1b428a55-1b50-4bcf-b2d9-06c2e8950768",+    "isActive": true,+    "balance": "$1,045.36",+    "picture": "http://placehold.it/32x32",+    "age": 25,+    "eyeColor": "blue",+    "name": "Adele Santana",+    "gender": "female",+    "company": "EBIDCO",+    "email": "adelesantana@ebidco.com",+    "phone": "+1 (981) 528-2138",+    "address": "117 Kent Avenue, Chamizal, Iowa, 4289",+    "about": "Culpa eu nostrud mollit voluptate consequat pariatur. Qui ex laboris velit cupidatat enim. Reprehenderit commodo eu excepteur ex elit amet dolore enim. Nisi dolor pariatur enim laborum voluptate Lorem magna ipsum enim aute do sunt. Ad consectetur velit laborum magna labore Lorem occaecat quis. Exercitation ipsum velit nostrud cupidatat consequat ex non velit deserunt pariatur officia. Magna occaecat Lorem qui aliqua id aliquip laborum.\r\n",+    "registered": "2014-10-01T21:15:54 +07:00",+    "latitude": 24.339451,+    "longitude": -38.920718,+    "tags": [+      "ullamco",+      "labore",+      "magna",+      "fugiat",+      "consectetur",+      "nostrud",+      "veniam"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Sharpe Haley"+      },+      {+        "id": 1,+        "name": "Patrice Horne"+      },+      {+        "id": 2,+        "name": "Melanie Sosa"+      }+    ],+    "greeting": "Hello, Adele Santana! You have 10 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a900e0eec7c0c194713",+    "index": 24,+    "guid": "cc7114a5-89ce-4fb6-9ad8-b5886360ab42",+    "isActive": true,+    "balance": "$2,505.31",+    "picture": "http://placehold.it/32x32",+    "age": 36,+    "eyeColor": "blue",+    "name": "Lindsey Colon",+    "gender": "male",+    "company": "XYLAR",+    "email": "lindseycolon@xylar.com",+    "phone": "+1 (952) 532-3896",+    "address": "144 Poly Place, Detroit, Federated States Of Micronesia, 2004",+    "about": "Ullamco nostrud Lorem duis duis aute sunt commodo Lorem. Esse cupidatat aliqua et laborum officia et. Ea magna est eiusmod id sit ea esse consectetur qui.\r\n",+    "registered": "2014-04-05T02:52:07 +07:00",+    "latitude": -55.350071,+    "longitude": -20.446672,+    "tags": [+      "id",+      "sit",+      "cillum",+      "id",+      "exercitation",+      "reprehenderit",+      "deserunt"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Kathleen Berger"+      },+      {+        "id": 1,+        "name": "Morales Tran"+      },+      {+        "id": 2,+        "name": "Dionne Hunter"+      }+    ],+    "greeting": "Hello, Lindsey Colon! You have 3 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90a20ec5bce57f2f55",+    "index": 25,+    "guid": "c1d3f95b-25dd-4b48-8fe8-9af5f62895e2",+    "isActive": true,+    "balance": "$1,609.28",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "green",+    "name": "Langley Moore",+    "gender": "male",+    "company": "ZYTRAX",+    "email": "langleymoore@zytrax.com",+    "phone": "+1 (912) 580-3688",+    "address": "747 Abbey Court, Odessa, Kentucky, 4688",+    "about": "Eiusmod adipisicing aliquip quis voluptate qui. Enim esse culpa elit id eu dolor culpa eiusmod. Deserunt ut ea ipsum ipsum non culpa ullamco non ipsum sunt cupidatat.\r\n",+    "registered": "2014-06-28T08:29:15 +07:00",+    "latitude": 65.464748,+    "longitude": -129.638837,+    "tags": [+      "deserunt",+      "cillum",+      "sint",+      "proident",+      "ad",+      "adipisicing",+      "mollit"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Mcguire Vance"+      },+      {+        "id": 1,+        "name": "Norma Buck"+      },+      {+        "id": 2,+        "name": "Janelle Bailey"+      }+    ],+    "greeting": "Hello, Langley Moore! You have 8 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a903c9a63ef7fccce96",+    "index": 26,+    "guid": "88c32c0f-a2c6-49c2-8261-bc323895067f",+    "isActive": false,+    "balance": "$3,748.41",+    "picture": "http://placehold.it/32x32",+    "age": 26,+    "eyeColor": "blue",+    "name": "Duran Bryan",+    "gender": "male",+    "company": "BULLZONE",+    "email": "duranbryan@bullzone.com",+    "phone": "+1 (911) 598-2827",+    "address": "903 Village Road, Cressey, New Jersey, 9174",+    "about": "Do in fugiat est deserunt in sit Lorem quis reprehenderit est ut tempor. Ullamco in veniam non quis cillum consectetur id. Elit exercitation reprehenderit et amet voluptate magna voluptate minim veniam enim exercitation aute aute esse. Exercitation magna voluptate laborum ipsum cupidatat exercitation ad eu aute deserunt et. Voluptate qui aute ut elit amet excepteur nostrud officia irure do.\r\n",+    "registered": "2014-01-29T12:32:05 +08:00",+    "latitude": -51.269785,+    "longitude": 79.015891,+    "tags": [+      "consequat",+      "id",+      "exercitation",+      "incididunt",+      "adipisicing",+      "laboris",+      "laboris"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Jenny Allison"+      },+      {+        "id": 1,+        "name": "Della Hobbs"+      },+      {+        "id": 2,+        "name": "Bradshaw Owens"+      }+    ],+    "greeting": "Hello, Duran Bryan! You have 5 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a907a2f07fbb3efec0f",+    "index": 27,+    "guid": "df997a84-5ec1-4f63-acb7-140b9fed981d",+    "isActive": true,+    "balance": "$1,249.61",+    "picture": "http://placehold.it/32x32",+    "age": 28,+    "eyeColor": "blue",+    "name": "Juarez House",+    "gender": "male",+    "company": "ZUVY",+    "email": "juarezhouse@zuvy.com",+    "phone": "+1 (841) 533-3140",+    "address": "494 Atlantic Avenue, Shasta, Nevada, 8475",+    "about": "Proident eu nostrud laboris adipisicing pariatur sint ipsum exercitation velit non incididunt. Qui cupidatat reprehenderit nostrud magna sunt aute nulla aliquip velit culpa commodo fugiat laborum. Dolore consectetur esse labore magna anim exercitation dolor velit qui sunt Lorem reprehenderit amet.\r\n",+    "registered": "2014-03-16T19:21:13 +07:00",+    "latitude": 57.96486,+    "longitude": 130.460435,+    "tags": [+      "incididunt",+      "reprehenderit",+      "consequat",+      "duis",+      "veniam",+      "nulla",+      "dolor"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Keri Lara"+      },+      {+        "id": 1,+        "name": "Celina Pace"+      },+      {+        "id": 2,+        "name": "Bush Haynes"+      }+    ],+    "greeting": "Hello, Juarez House! You have 7 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a903021f42c063be598",+    "index": 28,+    "guid": "1dc6349d-4354-42a9-9f73-7bc12d5ac9c2",+    "isActive": false,+    "balance": "$1,991.33",+    "picture": "http://placehold.it/32x32",+    "age": 26,+    "eyeColor": "blue",+    "name": "Sonja Horton",+    "gender": "female",+    "company": "VIDTO",+    "email": "sonjahorton@vidto.com",+    "phone": "+1 (990) 504-2432",+    "address": "612 River Street, Carrizo, California, 5778",+    "about": "Nisi reprehenderit occaecat anim ut minim aliqua aliquip velit veniam eiusmod reprehenderit laboris ad. Duis aliqua labore cillum proident est amet. Adipisicing nostrud proident labore laborum. Elit est sint ex veniam reprehenderit. Veniam ut dolor nulla tempor voluptate sit excepteur sit ut quis.\r\n",+    "registered": "2014-10-30T05:07:28 +07:00",+    "latitude": 85.37031,+    "longitude": -122.082636,+    "tags": [+      "tempor",+      "ex",+      "nostrud",+      "ullamco",+      "ullamco",+      "nisi",+      "cillum"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Phillips Henry"+      },+      {+        "id": 1,+        "name": "Leanne Sexton"+      },+      {+        "id": 2,+        "name": "Alisha Chang"+      }+    ],+    "greeting": "Hello, Sonja Horton! You have 1 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a903a33ff6bb03e049a",+    "index": 29,+    "guid": "4ef3a65d-5407-400b-aace-62bbb8a83c6a",+    "isActive": true,+    "balance": "$2,823.03",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "blue",+    "name": "Lidia Hewitt",+    "gender": "female",+    "company": "PROWASTE",+    "email": "lidiahewitt@prowaste.com",+    "phone": "+1 (909) 562-3312",+    "address": "625 Ralph Avenue, Kiskimere, Maryland, 2033",+    "about": "Eu adipisicing eiusmod laboris veniam sunt id ad eiusmod consectetur nisi. Esse nulla ipsum Lorem nisi consequat laborum. Veniam ea exercitation ullamco pariatur consectetur. Cupidatat velit excepteur ex eu sunt id. In velit reprehenderit pariatur velit. Voluptate nostrud deserunt qui mollit et tempor nostrud eiusmod adipisicing ad est laborum. Fugiat nisi sit nulla eu ad.\r\n",+    "registered": "2014-01-15T00:05:42 +08:00",+    "latitude": -50.566931,+    "longitude": -149.036259,+    "tags": [+      "in",+      "ipsum",+      "tempor",+      "magna",+      "aliqua",+      "duis",+      "incididunt"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Allie Baker"+      },+      {+        "id": 1,+        "name": "Valdez Giles"+      },+      {+        "id": 2,+        "name": "Knox Vargas"+      }+    ],+    "greeting": "Hello, Lidia Hewitt! You have 3 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90ce7ef56e53f98790",+    "index": 30,+    "guid": "9ae34b38-098b-4de6-aa0f-90359571ddf2",+    "isActive": false,+    "balance": "$3,152.82",+    "picture": "http://placehold.it/32x32",+    "age": 38,+    "eyeColor": "brown",+    "name": "Nieves Ewing",+    "gender": "male",+    "company": "QNEKT",+    "email": "nievesewing@qnekt.com",+    "phone": "+1 (888) 460-2384",+    "address": "425 Highland Place, Hampstead, Washington, 7019",+    "about": "Ipsum aliquip ullamco labore aliquip et. Eu pariatur exercitation ex fugiat fugiat. Nulla voluptate et cupidatat deserunt mollit et incididunt. Deserunt anim qui cupidatat veniam et et dolore qui sunt tempor ipsum. In et voluptate excepteur incididunt dolore cupidatat exercitation ullamco dolore Lorem nostrud sunt nostrud. Occaecat amet ut laborum laborum aliqua est incididunt ea excepteur commodo. Ipsum et elit nisi duis pariatur occaecat.\r\n",+    "registered": "2014-06-15T18:44:29 +07:00",+    "latitude": 8.010315,+    "longitude": 69.049129,+    "tags": [+      "exercitation",+      "eiusmod",+      "voluptate",+      "ullamco",+      "consectetur",+      "reprehenderit",+      "enim"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Maggie Rodriguez"+      },+      {+        "id": 1,+        "name": "Evans Roach"+      },+      {+        "id": 2,+        "name": "Greer Mccoy"+      }+    ],+    "greeting": "Hello, Nieves Ewing! You have 7 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a9049aa4bbedefd311d",+    "index": 31,+    "guid": "471d52a6-da38-4015-8d7a-6fe215a032d3",+    "isActive": false,+    "balance": "$1,456.93",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "green",+    "name": "Reyna Clay",+    "gender": "female",+    "company": "KINETICA",+    "email": "reynaclay@kinetica.com",+    "phone": "+1 (865) 425-3747",+    "address": "480 Dakota Place, Kimmell, Utah, 6677",+    "about": "Tempor esse ex amet aliqua incididunt incididunt qui commodo laborum incididunt deserunt elit id consequat. Proident duis ut ullamco non ea magna fugiat fugiat Lorem minim. Incididunt tempor nostrud proident irure laboris consectetur elit labore adipisicing fugiat nulla quis ipsum consequat. Tempor mollit pariatur irure in nisi minim magna excepteur. Aliquip et laborum cillum adipisicing consequat.\r\n",+    "registered": "2014-10-30T08:53:04 +07:00",+    "latitude": 38.437675,+    "longitude": 42.847793,+    "tags": [+      "incididunt",+      "est",+      "mollit",+      "nulla",+      "ipsum",+      "ea",+      "ea"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Glenna Macdonald"+      },+      {+        "id": 1,+        "name": "Bertha Meadows"+      },+      {+        "id": 2,+        "name": "Oneill Barnes"+      }+    ],+    "greeting": "Hello, Reyna Clay! You have 6 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a900238319b9b407aa0",+    "index": 32,+    "guid": "fa5c52e1-9a9d-44d4-8e6b-5a65221ab142",+    "isActive": true,+    "balance": "$3,113.15",+    "picture": "http://placehold.it/32x32",+    "age": 24,+    "eyeColor": "blue",+    "name": "Felicia Harris",+    "gender": "female",+    "company": "FITCORE",+    "email": "feliciaharris@fitcore.com",+    "phone": "+1 (814) 449-2730",+    "address": "641 Hazel Court, Bawcomville, Wisconsin, 4111",+    "about": "Magna in elit aute ipsum anim dolore et exercitation sunt occaecat velit. Sint tempor nulla sit laborum dolor ex irure nisi nulla veniam in labore laborum. Nulla magna excepteur exercitation aute occaecat consequat laborum Lorem velit occaecat aliqua qui. Id in aliqua dolore fugiat duis elit laborum commodo cillum ex aute minim eu.\r\n",+    "registered": "2014-04-15T21:31:39 +07:00",+    "latitude": -58.891583,+    "longitude": -162.554134,+    "tags": [+      "eiusmod",+      "dolor",+      "enim",+      "cupidatat",+      "labore",+      "sunt",+      "consectetur"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Rich Lott"+      },+      {+        "id": 1,+        "name": "Rebecca Cardenas"+      },+      {+        "id": 2,+        "name": "Jarvis Barron"+      }+    ],+    "greeting": "Hello, Felicia Harris! You have 7 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90f03941c94fe50d08",+    "index": 33,+    "guid": "49070cf3-b2f3-445e-86ec-3ae9cddc474d",+    "isActive": false,+    "balance": "$1,105.05",+    "picture": "http://placehold.it/32x32",+    "age": 35,+    "eyeColor": "green",+    "name": "Josefina Holland",+    "gender": "female",+    "company": "GOGOL",+    "email": "josefinaholland@gogol.com",+    "phone": "+1 (809) 411-2991",+    "address": "778 McKibben Street, Whitehaven, Louisiana, 2079",+    "about": "Cillum ipsum cupidatat et dolor minim aliqua. Laborum culpa magna ullamco nulla ut labore deserunt amet sunt est esse do. Consequat aliquip eiusmod ipsum tempor. Voluptate exercitation nisi nulla dolor esse ullamco occaecat. Sint minim reprehenderit anim tempor deserunt sit exercitation. Qui proident cillum eu voluptate adipisicing velit tempor sunt sunt ipsum. Enim anim ea ea eu excepteur excepteur laboris eu.\r\n",+    "registered": "2014-09-13T12:46:51 +07:00",+    "latitude": 81.172596,+    "longitude": -151.851605,+    "tags": [+      "velit",+      "ad",+      "tempor",+      "tempor",+      "adipisicing",+      "nulla",+      "minim"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Lester Woods"+      },+      {+        "id": 1,+        "name": "Audra Shepherd"+      },+      {+        "id": 2,+        "name": "Chandler Church"+      }+    ],+    "greeting": "Hello, Josefina Holland! You have 5 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a9008a3955509cf065f",+    "index": 34,+    "guid": "4c838bee-e8b1-4c22-b8ad-e0e5d0822334",+    "isActive": false,+    "balance": "$3,032.13",+    "picture": "http://placehold.it/32x32",+    "age": 32,+    "eyeColor": "green",+    "name": "Susie Cash",+    "gender": "female",+    "company": "DOGSPA",+    "email": "susiecash@dogspa.com",+    "phone": "+1 (991) 447-2298",+    "address": "361 Quincy Street, Duryea, Florida, 7538",+    "about": "Officia eu non proident ad ea quis eu ea amet irure aliqua qui. Ea in laborum do sit. Dolor proident voluptate excepteur sit. Tempor nulla anim ex proident ipsum laboris laboris cupidatat esse dolore ex fugiat proident. Excepteur exercitation pariatur ex velit. In adipisicing eu eiusmod elit dolore ullamco nulla sit ut ut anim aliquip. Et eu eu aliquip ex aute aliquip veniam sint pariatur non incididunt in aliqua sit.\r\n",+    "registered": "2014-09-14T22:55:19 +07:00",+    "latitude": 8.46119,+    "longitude": -1.171475,+    "tags": [+      "voluptate",+      "irure",+      "ex",+      "proident",+      "nulla",+      "in",+      "esse"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Cassie Whitley"+      },+      {+        "id": 1,+        "name": "Shawna Todd"+      },+      {+        "id": 2,+        "name": "Antoinette Brooks"+      }+    ],+    "greeting": "Hello, Susie Cash! You have 1 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a9079c5bce30e9c0a68",+    "index": 35,+    "guid": "7a70e0df-c23b-435d-8d19-864cc1bd09e6",+    "isActive": false,+    "balance": "$2,523.44",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "brown",+    "name": "Marquez Hartman",+    "gender": "male",+    "company": "BUZZMAKER",+    "email": "marquezhartman@buzzmaker.com",+    "phone": "+1 (880) 574-2420",+    "address": "326 Church Avenue, Yardville, Indiana, 6743",+    "about": "Ullamco reprehenderit pariatur veniam enim est nulla laboris ullamco eiusmod eu Lorem amet in amet. Incididunt consectetur reprehenderit tempor Lorem aute eiusmod laborum sunt mollit excepteur qui ea enim. Consectetur enim excepteur proident incididunt adipisicing duis est amet quis proident laboris. Consectetur Lorem consequat incididunt eiusmod mollit id amet velit quis ipsum labore. Cupidatat id minim cillum qui consequat quis non quis irure dolor voluptate ea eu.\r\n",+    "registered": "2014-06-16T07:23:30 +07:00",+    "latitude": -88.970617,+    "longitude": -28.068887,+    "tags": [+      "nostrud",+      "adipisicing",+      "quis",+      "voluptate",+      "dolore",+      "dolore",+      "reprehenderit"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Florence David"+      },+      {+        "id": 1,+        "name": "Lynn Mcleod"+      },+      {+        "id": 2,+        "name": "Catherine Abbott"+      }+    ],+    "greeting": "Hello, Marquez Hartman! You have 10 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a902bf5baf83c4fafcd",+    "index": 36,+    "guid": "56ac4022-1ed3-4298-9b70-c6060c69b13c",+    "isActive": false,+    "balance": "$1,162.32",+    "picture": "http://placehold.it/32x32",+    "age": 35,+    "eyeColor": "green",+    "name": "Bishop Gibbs",+    "gender": "male",+    "company": "MICROLUXE",+    "email": "bishopgibbs@microluxe.com",+    "phone": "+1 (808) 584-2587",+    "address": "801 Exeter Street, Trucksville, New Hampshire, 4871",+    "about": "Incididunt sit eu sunt cupidatat aute do eu eu culpa. Laborum adipisicing sit anim sit dolor labore commodo minim proident ullamco laboris sit irure. Duis dolore cupidatat ullamco anim reprehenderit aliquip incididunt sunt eu id non proident non.\r\n",+    "registered": "2014-09-10T02:39:14 +07:00",+    "latitude": -3.268064,+    "longitude": 149.311591,+    "tags": [+      "enim",+      "aute",+      "commodo",+      "consectetur",+      "Lorem",+      "est",+      "cillum"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Head Pickett"+      },+      {+        "id": 1,+        "name": "Thornton Russo"+      },+      {+        "id": 2,+        "name": "Hooper Rivera"+      }+    ],+    "greeting": "Hello, Bishop Gibbs! You have 9 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90a4406555b5bdab8f",+    "index": 37,+    "guid": "0f052dd2-283e-441e-86d7-b7f7b47224f1",+    "isActive": true,+    "balance": "$3,306.81",+    "picture": "http://placehold.it/32x32",+    "age": 34,+    "eyeColor": "brown",+    "name": "Carr Strickland",+    "gender": "male",+    "company": "EXERTA",+    "email": "carrstrickland@exerta.com",+    "phone": "+1 (862) 455-3845",+    "address": "730 Aberdeen Street, Klondike, Kansas, 4412",+    "about": "Pariatur velit qui Lorem cillum labore veniam minim. Nisi reprehenderit commodo consectetur commodo velit. Ipsum dolor ea mollit excepteur minim do excepteur. Aliquip cillum quis nostrud cillum duis eu laborum reprehenderit adipisicing adipisicing do exercitation. Laborum Lorem sunt voluptate qui quis officia nisi et elit sint veniam. Lorem velit ad do amet labore veniam consectetur.\r\n",+    "registered": "2014-01-19T10:53:58 +08:00",+    "latitude": -45.243563,+    "longitude": -17.8448,+    "tags": [+      "mollit",+      "ex",+      "qui",+      "fugiat",+      "consequat",+      "consectetur",+      "do"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Rosario Gomez"+      },+      {+        "id": 1,+        "name": "Robinson Robinson"+      },+      {+        "id": 2,+        "name": "Vicki Moreno"+      }+    ],+    "greeting": "Hello, Carr Strickland! You have 2 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a9097f6a585321fe001",+    "index": 38,+    "guid": "eee159c2-73ac-44b7-9054-d72295d3178a",+    "isActive": true,+    "balance": "$3,336.97",+    "picture": "http://placehold.it/32x32",+    "age": 30,+    "eyeColor": "brown",+    "name": "Stephens Harper",+    "gender": "male",+    "company": "KIDSTOCK",+    "email": "stephensharper@kidstock.com",+    "phone": "+1 (989) 464-3887",+    "address": "315 Hewes Street, Cuylerville, Pennsylvania, 7331",+    "about": "Et ea Lorem labore consequat laboris. Aliqua irure elit aliqua ad fugiat. Commodo cupidatat incididunt ut nostrud consequat elit ad esse magna nisi nostrud dolore eu. Minim incididunt esse ullamco esse ullamco deserunt reprehenderit commodo ut. Quis sint cupidatat excepteur et laboris incididunt id esse irure nostrud sint nostrud ut pariatur. Pariatur officia aute ullamco laboris nisi elit quis labore Lorem minim ad. Ea esse anim commodo fugiat exercitation voluptate eiusmod aliquip amet enim nulla mollit excepteur nisi.\r\n",+    "registered": "2014-03-02T06:45:25 +08:00",+    "latitude": -88.39292,+    "longitude": -121.170605,+    "tags": [+      "ullamco",+      "est",+      "mollit",+      "id",+      "commodo",+      "Lorem",+      "nostrud"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Castaneda Dillon"+      },+      {+        "id": 1,+        "name": "Morin Hodge"+      },+      {+        "id": 2,+        "name": "Vincent Lamb"+      }+    ],+    "greeting": "Hello, Stephens Harper! You have 2 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90357d07212fdefd7a",+    "index": 39,+    "guid": "160a80a4-8e5d-483a-93ed-0a37ee359f04",+    "isActive": true,+    "balance": "$1,588.64",+    "picture": "http://placehold.it/32x32",+    "age": 32,+    "eyeColor": "green",+    "name": "Espinoza May",+    "gender": "male",+    "company": "ZIDOX",+    "email": "espinozamay@zidox.com",+    "phone": "+1 (955) 420-2244",+    "address": "614 Alice Court, Vienna, Delaware, 5018",+    "about": "Pariatur voluptate culpa enim enim sunt dolor laborum consequat officia est nostrud. Ad pariatur labore reprehenderit cillum dolor consequat quis eu fugiat. Ut fugiat do dolor minim voluptate incididunt laboris magna deserunt. Culpa incididunt fugiat nostrud qui incididunt velit laboris deserunt exercitation velit.\r\n",+    "registered": "2014-09-16T06:10:45 +07:00",+    "latitude": -28.413217,+    "longitude": -76.45198,+    "tags": [+      "ullamco",+      "ut",+      "nulla",+      "consequat",+      "ea",+      "in",+      "commodo"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Virginia Obrien"+      },+      {+        "id": 1,+        "name": "Snider Hopper"+      },+      {+        "id": 2,+        "name": "Fannie Harrell"+      }+    ],+    "greeting": "Hello, Espinoza May! You have 3 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a901e753e41d1232a42",+    "index": 40,+    "guid": "7f3923e7-2fad-4210-b051-bd805e505d06",+    "isActive": false,+    "balance": "$2,512.14",+    "picture": "http://placehold.it/32x32",+    "age": 28,+    "eyeColor": "green",+    "name": "Morrison Guerrero",+    "gender": "male",+    "company": "MARQET",+    "email": "morrisonguerrero@marqet.com",+    "phone": "+1 (881) 456-3335",+    "address": "157 Huntington Street, Topaz, Georgia, 6068",+    "about": "Velit cupidatat eiusmod elit ut adipisicing. Proident pariatur consequat ullamco velit dolore do esse adipisicing non est ea. Velit non amet nisi aliqua est veniam dolor. Cillum id labore qui ut aute pariatur exercitation ut incididunt velit aute.\r\n",+    "registered": "2014-11-12T21:01:15 +08:00",+    "latitude": -43.420946,+    "longitude": 23.215515,+    "tags": [+      "sit",+      "dolore",+      "aliqua",+      "esse",+      "et",+      "cillum",+      "mollit"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Pamela Stanton"+      },+      {+        "id": 1,+        "name": "Spence Banks"+      },+      {+        "id": 2,+        "name": "Newton Cooley"+      }+    ],+    "greeting": "Hello, Morrison Guerrero! You have 4 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a9098c06d55fa03398f",+    "index": 41,+    "guid": "c17e4f56-ca2b-48fd-bbc4-aea053062ebd",+    "isActive": false,+    "balance": "$3,405.25",+    "picture": "http://placehold.it/32x32",+    "age": 26,+    "eyeColor": "brown",+    "name": "Janna Porter",+    "gender": "female",+    "company": "NIMON",+    "email": "jannaporter@nimon.com",+    "phone": "+1 (974) 475-2497",+    "address": "231 Wythe Place, Stonybrook, Alaska, 6291",+    "about": "Veniam aute dolor Lorem dolore enim eiusmod veniam esse pariatur duis nisi. Eu sit sunt in exercitation amet veniam reprehenderit voluptate proident officia. Dolore aliquip laboris veniam cupidatat non cupidatat ipsum esse labore Lorem reprehenderit ex. Amet magna do officia proident laborum laboris enim. Ea sunt quis officia minim ea in id cillum. Aute ipsum aliquip fugiat tempor proident sit pariatur duis fugiat fugiat esse cillum eiusmod laboris.\r\n",+    "registered": "2014-08-21T22:08:24 +07:00",+    "latitude": -43.52587,+    "longitude": 143.40506,+    "tags": [+      "ipsum",+      "consequat",+      "labore",+      "tempor",+      "ipsum",+      "exercitation",+      "sint"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Bray Francis"+      },+      {+        "id": 1,+        "name": "Whitley Guthrie"+      },+      {+        "id": 2,+        "name": "Christa Short"+      }+    ],+    "greeting": "Hello, Janna Porter! You have 1 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90ddf3f9e967357339",+    "index": 42,+    "guid": "5b194b7d-c5ca-4cdd-9239-6aa6f9b28e2f",+    "isActive": false,+    "balance": "$1,601.96",+    "picture": "http://placehold.it/32x32",+    "age": 31,+    "eyeColor": "green",+    "name": "Sandoval Melton",+    "gender": "male",+    "company": "GENMEX",+    "email": "sandovalmelton@genmex.com",+    "phone": "+1 (826) 536-3504",+    "address": "726 Lester Court, Gracey, Colorado, 4092",+    "about": "Fugiat pariatur elit Lorem amet fugiat tempor. Quis sint fugiat officia deserunt voluptate fugiat aliquip reprehenderit est laborum. Ut id ullamco Lorem esse occaecat eu officia veniam velit. Aliquip nisi voluptate id aliquip qui tempor commodo occaecat velit adipisicing nisi cillum id adipisicing.\r\n",+    "registered": "2014-09-05T08:54:55 +07:00",+    "latitude": -66.159672,+    "longitude": -135.605108,+    "tags": [+      "deserunt",+      "minim",+      "nulla",+      "ea",+      "tempor",+      "reprehenderit",+      "nulla"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Veronica Goodwin"+      },+      {+        "id": 1,+        "name": "Heather Pena"+      },+      {+        "id": 2,+        "name": "Lynch Crane"+      }+    ],+    "greeting": "Hello, Sandoval Melton! You have 2 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a904d114bb57f0826af",+    "index": 43,+    "guid": "57e4715d-f7e7-4843-9844-638648315628",+    "isActive": false,+    "balance": "$1,820.21",+    "picture": "http://placehold.it/32x32",+    "age": 34,+    "eyeColor": "blue",+    "name": "Flynn Fitzgerald",+    "gender": "male",+    "company": "ORBEAN",+    "email": "flynnfitzgerald@orbean.com",+    "phone": "+1 (931) 578-2443",+    "address": "662 Degraw Street, Morgandale, Alabama, 5945",+    "about": "Nulla anim qui duis ea do consectetur eiusmod commodo. Minim sunt aliqua velit ullamco velit dolor in amet. Eiusmod Lorem sint ea ea nisi ullamco ut officia magna id adipisicing. Ut eu minim pariatur incididunt non nisi in nostrud culpa magna anim. Veniam dolor consequat cillum sunt elit.\r\n",+    "registered": "2014-06-21T08:11:23 +07:00",+    "latitude": 17.108863,+    "longitude": -21.608292,+    "tags": [+      "officia",+      "quis",+      "sint",+      "ipsum",+      "esse",+      "commodo",+      "aute"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Browning Mcdonald"+      },+      {+        "id": 1,+        "name": "Austin Lane"+      },+      {+        "id": 2,+        "name": "Blankenship Ferrell"+      }+    ],+    "greeting": "Hello, Flynn Fitzgerald! You have 6 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a903a4a0629f547f5ab",+    "index": 44,+    "guid": "1e128e33-65bf-4420-ae93-f228d030401c",+    "isActive": false,+    "balance": "$3,158.96",+    "picture": "http://placehold.it/32x32",+    "age": 25,+    "eyeColor": "brown",+    "name": "Holden Golden",+    "gender": "male",+    "company": "QABOOS",+    "email": "holdengolden@qaboos.com",+    "phone": "+1 (825) 535-2422",+    "address": "892 Vandervoort Place, Hessville, Guam, 3942",+    "about": "Non sunt cupidatat ipsum nostrud qui ad ex nostrud fugiat laboris minim. Aliquip dolore est proident aliquip in non culpa. Minim ut laboris duis proident commodo occaecat duis duis cupidatat incididunt aliqua. Ad qui anim non occaecat excepteur labore consequat Lorem.\r\n",+    "registered": "2014-09-11T00:33:16 +07:00",+    "latitude": -3.274271,+    "longitude": -151.539207,+    "tags": [+      "nostrud",+      "non",+      "sint",+      "laborum",+      "deserunt",+      "velit",+      "sit"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Barbara Sharpe"+      },+      {+        "id": 1,+        "name": "Jerri Martinez"+      },+      {+        "id": 2,+        "name": "Ronda Montoya"+      }+    ],+    "greeting": "Hello, Holden Golden! You have 3 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a9079e20c148518a60a",+    "index": 45,+    "guid": "90fa284f-6cba-42d4-8484-6edb1ffc260b",+    "isActive": false,+    "balance": "$1,739.35",+    "picture": "http://placehold.it/32x32",+    "age": 27,+    "eyeColor": "blue",+    "name": "Maxwell Hodges",+    "gender": "male",+    "company": "DOGTOWN",+    "email": "maxwellhodges@dogtown.com",+    "phone": "+1 (962) 527-3585",+    "address": "696 Baughman Place, Cucumber, South Carolina, 5454",+    "about": "Officia ea in non veniam ipsum ea magna enim velit. Enim mollit duis consectetur magna fugiat nostrud cillum duis. Voluptate qui nostrud amet ea eiusmod consectetur cupidatat fugiat in eiusmod amet esse excepteur aute. Magna qui duis ex qui irure esse amet. Quis amet ex esse aliquip mollit. Deserunt consectetur eiusmod culpa reprehenderit. Duis quis excepteur non in consectetur commodo.\r\n",+    "registered": "2014-03-20T11:37:19 +07:00",+    "latitude": 19.760315,+    "longitude": -26.731699,+    "tags": [+      "magna",+      "aute",+      "consectetur",+      "labore",+      "sunt",+      "pariatur",+      "excepteur"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Violet Vincent"+      },+      {+        "id": 1,+        "name": "West Dorsey"+      },+      {+        "id": 2,+        "name": "Concepcion Hull"+      }+    ],+    "greeting": "Hello, Maxwell Hodges! You have 3 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a903c504d648884f367",+    "index": 46,+    "guid": "7fd30275-a097-41e0-8924-252f0a14d6ba",+    "isActive": false,+    "balance": "$1,153.05",+    "picture": "http://placehold.it/32x32",+    "age": 22,+    "eyeColor": "brown",+    "name": "Chasity Day",+    "gender": "female",+    "company": "EQUITAX",+    "email": "chasityday@equitax.com",+    "phone": "+1 (900) 484-3047",+    "address": "858 Gelston Avenue, Succasunna, Arkansas, 3818",+    "about": "Est ullamco deserunt cillum enim velit velit magna qui nisi eiusmod enim officia sit voluptate. Laboris laborum elit nostrud sit in elit labore occaecat mollit Lorem. Aliquip ipsum dolore cupidatat ad anim sint non. Commodo ut fugiat ut dolor irure id velit enim in Lorem.\r\n",+    "registered": "2014-01-05T08:26:01 +08:00",+    "latitude": -34.705083,+    "longitude": -77.213981,+    "tags": [+      "consectetur",+      "velit",+      "enim",+      "excepteur",+      "ipsum",+      "non",+      "adipisicing"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Judy Trevino"+      },+      {+        "id": 1,+        "name": "Rosie Cervantes"+      },+      {+        "id": 2,+        "name": "Stella Cortez"+      }+    ],+    "greeting": "Hello, Chasity Day! You have 1 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90ac6406c3b9606052",+    "index": 47,+    "guid": "9bcd39b8-10db-40cc-a9f0-73e8179f181b",+    "isActive": true,+    "balance": "$1,755.70",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "green",+    "name": "Richards Mcfadden",+    "gender": "male",+    "company": "ZILLACOM",+    "email": "richardsmcfadden@zillacom.com",+    "phone": "+1 (883) 447-2941",+    "address": "241 Turnbull Avenue, Chesterfield, Ohio, 7594",+    "about": "Fugiat ut qui qui et Lorem ipsum do anim veniam. Sunt ex Lorem et nostrud consectetur esse nostrud qui minim ut veniam commodo. Cillum enim laboris aliquip sunt quis ut et adipisicing deserunt. Est aute amet elit non duis deserunt nisi quis excepteur do velit. Nostrud laboris ullamco sunt occaecat Lorem nostrud laboris.\r\n",+    "registered": "2014-07-04T03:08:44 +07:00",+    "latitude": -66.813737,+    "longitude": 75.337073,+    "tags": [+      "elit",+      "consequat",+      "excepteur",+      "qui",+      "deserunt",+      "sint",+      "ipsum"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Mercado Quinn"+      },+      {+        "id": 1,+        "name": "Lucia Roberts"+      },+      {+        "id": 2,+        "name": "Essie Cohen"+      }+    ],+    "greeting": "Hello, Richards Mcfadden! You have 5 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a9033409e09e42cf3f1",+    "index": 48,+    "guid": "6ea51613-14f0-42b7-97c6-eb7a5cc32226",+    "isActive": true,+    "balance": "$3,907.64",+    "picture": "http://placehold.it/32x32",+    "age": 31,+    "eyeColor": "blue",+    "name": "Sargent Harrington",+    "gender": "male",+    "company": "DIGINETIC",+    "email": "sargentharrington@diginetic.com",+    "phone": "+1 (974) 427-2742",+    "address": "883 Kermit Place, Rehrersburg, Virgin Islands, 4044",+    "about": "Officia eiusmod do ut ipsum voluptate aute mollit minim ea incididunt ipsum commodo. Qui aute commodo dolor id pariatur ullamco adipisicing duis irure reprehenderit aliquip ullamco consequat. Sunt ad non deserunt velit consectetur ipsum. Sit voluptate aliquip nisi ea pariatur proident ut eu cillum. Irure sunt ad aliqua et enim. Deserunt deserunt incididunt Lorem commodo aliqua.\r\n",+    "registered": "2014-06-16T00:32:02 +07:00",+    "latitude": -88.301682,+    "longitude": -16.268399,+    "tags": [+      "Lorem",+      "reprehenderit",+      "consequat",+      "officia",+      "velit",+      "ad",+      "ex"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Dolly Swanson"+      },+      {+        "id": 1,+        "name": "Jeannette Underwood"+      },+      {+        "id": 2,+        "name": "Ayers Wheeler"+      }+    ],+    "greeting": "Hello, Sargent Harrington! You have 3 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a9083fe43074bb5b9c8",+    "index": 49,+    "guid": "d5835fea-0882-4e20-b86e-6dd8b9534b49",+    "isActive": false,+    "balance": "$2,481.41",+    "picture": "http://placehold.it/32x32",+    "age": 22,+    "eyeColor": "green",+    "name": "Kristin Perez",+    "gender": "female",+    "company": "JAMNATION",+    "email": "kristinperez@jamnation.com",+    "phone": "+1 (917) 575-2693",+    "address": "737 Schroeders Avenue, Chemung, Nebraska, 8601",+    "about": "Voluptate id id mollit in aliquip aliquip duis cupidatat elit voluptate proident sit sunt voluptate. Irure ipsum esse duis culpa esse et do officia consequat velit commodo Lorem. Dolore incididunt proident proident officia aliqua mollit nisi exercitation consectetur. Est dolore consectetur aliqua occaecat est. Labore nostrud ipsum aliquip labore elit aliquip magna ex esse do consequat minim id. Sit sint ea ad irure voluptate occaecat duis magna. Sint ex minim irure anim sint do cillum.\r\n",+    "registered": "2014-08-12T23:35:39 +07:00",+    "latitude": 75.002428,+    "longitude": 12.266159,+    "tags": [+      "anim",+      "exercitation",+      "excepteur",+      "amet",+      "aute",+      "mollit",+      "aliquip"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Gilliam Steele"+      },+      {+        "id": 1,+        "name": "Loretta Brennan"+      },+      {+        "id": 2,+        "name": "Ratliff Norton"+      }+    ],+    "greeting": "Hello, Kristin Perez! You have 9 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90f594e03626363339",+    "index": 50,+    "guid": "bdb8284c-7b55-4791-90c0-d9e4abecd91f",+    "isActive": true,+    "balance": "$1,906.85",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "green",+    "name": "Petra Scott",+    "gender": "female",+    "company": "BRAINCLIP",+    "email": "petrascott@brainclip.com",+    "phone": "+1 (942) 449-2471",+    "address": "759 Coleridge Street, Tuskahoma, Virginia, 9943",+    "about": "Consectetur magna consequat ea est. Minim veniam culpa deserunt aliqua in dolor ex aliqua occaecat reprehenderit. Proident in mollit ad est excepteur anim quis aliquip non consequat minim cillum deserunt. Occaecat sint ad et irure sit ad ad sit sint quis sunt nisi.\r\n",+    "registered": "2014-11-12T20:54:05 +08:00",+    "latitude": -64.192199,+    "longitude": -144.535209,+    "tags": [+      "cillum",+      "id",+      "aliqua",+      "reprehenderit",+      "officia",+      "aliquip",+      "in"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Holmes Rasmussen"+      },+      {+        "id": 1,+        "name": "Leach Hickman"+      },+      {+        "id": 2,+        "name": "Noelle Battle"+      }+    ],+    "greeting": "Hello, Petra Scott! You have 9 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a902f79c4cdada83391",+    "index": 51,+    "guid": "c79aaabd-212b-4dc8-b1b5-de14362b550c",+    "isActive": true,+    "balance": "$2,845.25",+    "picture": "http://placehold.it/32x32",+    "age": 32,+    "eyeColor": "brown",+    "name": "Kelli Gates",+    "gender": "female",+    "company": "MUSANPOLY",+    "email": "kelligates@musanpoly.com",+    "phone": "+1 (899) 414-3276",+    "address": "888 Elm Place, Grayhawk, Wyoming, 8032",+    "about": "Nisi excepteur laboris duis magna dolore occaecat dolor cupidatat. Ut commodo proident incididunt ea anim enim deserunt laboris occaecat anim cillum. In amet exercitation officia mollit officia quis exercitation aliqua culpa ullamco consequat excepteur aute mollit. Aliqua tempor consequat ullamco consequat qui duis tempor ex est aliqua id nulla Lorem occaecat. Et laborum culpa pariatur et ad minim. Nulla ad eiusmod pariatur velit aliquip magna duis duis tempor. Nisi ea reprehenderit aliquip magna esse occaecat consectetur ullamco esse.\r\n",+    "registered": "2014-03-01T15:11:58 +08:00",+    "latitude": 30.679655,+    "longitude": -175.200369,+    "tags": [+      "laborum",+      "non",+      "pariatur",+      "ea",+      "non",+      "proident",+      "culpa"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Coleman Mejia"+      },+      {+        "id": 1,+        "name": "Meyers Sellers"+      },+      {+        "id": 2,+        "name": "Stuart Carney"+      }+    ],+    "greeting": "Hello, Kelli Gates! You have 1 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a9040ef999266e0142c",+    "index": 52,+    "guid": "cb9bc903-5e95-4918-91ed-8485d75489fa",+    "isActive": true,+    "balance": "$1,352.24",+    "picture": "http://placehold.it/32x32",+    "age": 29,+    "eyeColor": "green",+    "name": "Maricela Conrad",+    "gender": "female",+    "company": "QUIZKA",+    "email": "maricelaconrad@quizka.com",+    "phone": "+1 (924) 592-2199",+    "address": "339 Virginia Place, Lutsen, Marshall Islands, 1479",+    "about": "Quis commodo cupidatat mollit et deserunt id ut anim nostrud nisi mollit esse commodo laborum. Cillum exercitation anim cillum esse quis consequat. Dolor laboris exercitation irure ullamco excepteur ipsum deserunt. Anim veniam dolore labore exercitation et consectetur eiusmod eu. Aliquip velit consectetur nostrud dolore.\r\n",+    "registered": "2014-06-15T22:10:22 +07:00",+    "latitude": -0.554318,+    "longitude": -65.103334,+    "tags": [+      "adipisicing",+      "irure",+      "deserunt",+      "culpa",+      "cupidatat",+      "do",+      "occaecat"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Gentry Holden"+      },+      {+        "id": 1,+        "name": "Dillard Herrera"+      },+      {+        "id": 2,+        "name": "Guzman Patton"+      }+    ],+    "greeting": "Hello, Maricela Conrad! You have 1 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a905369b0bb27f85607",+    "index": 53,+    "guid": "fa3a125f-2d10-4015-a0fd-68d7e2401a31",+    "isActive": false,+    "balance": "$2,858.28",+    "picture": "http://placehold.it/32x32",+    "age": 34,+    "eyeColor": "green",+    "name": "Simpson Cleveland",+    "gender": "male",+    "company": "ZAPPIX",+    "email": "simpsoncleveland@zappix.com",+    "phone": "+1 (808) 572-3724",+    "address": "202 Georgia Avenue, Jamestown, Texas, 6347",+    "about": "Reprehenderit elit in duis sunt quis consequat mollit ut consequat amet. Incididunt non sint culpa non mollit incididunt elit irure sint excepteur esse sit ut fugiat. Ullamco esse culpa excepteur magna laborum sunt magna ut reprehenderit aute laboris ullamco Lorem ea. Culpa ut sit amet dolor adipisicing veniam non occaecat ex ad ea. Quis nostrud sit mollit aliqua adipisicing.\r\n",+    "registered": "2014-10-27T07:51:50 +07:00",+    "latitude": -34.024135,+    "longitude": 66.799767,+    "tags": [+      "anim",+      "pariatur",+      "fugiat",+      "reprehenderit",+      "ullamco",+      "labore",+      "fugiat"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Hester Howell"+      },+      {+        "id": 1,+        "name": "Deena King"+      },+      {+        "id": 2,+        "name": "Wilkerson Fox"+      }+    ],+    "greeting": "Hello, Simpson Cleveland! You have 10 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a900271aa8695bc5cdf",+    "index": 54,+    "guid": "501e7876-6b3f-4f2e-bbaf-914e6ff23845",+    "isActive": false,+    "balance": "$2,015.78",+    "picture": "http://placehold.it/32x32",+    "age": 23,+    "eyeColor": "brown",+    "name": "Queen Mckay",+    "gender": "female",+    "company": "PROXSOFT",+    "email": "queenmckay@proxsoft.com",+    "phone": "+1 (954) 439-2402",+    "address": "749 Wakeman Place, Sidman, Massachusetts, 3345",+    "about": "Culpa irure velit cupidatat voluptate ad non anim sit sunt in esse adipisicing. Officia amet Lorem et id eiusmod non commodo deserunt irure tempor aute fugiat est cupidatat. Ut amet ad consequat nulla in in deserunt minim ipsum adipisicing eu adipisicing nisi nulla. Qui culpa sunt aute amet est consequat excepteur occaecat voluptate in do. In labore aute sit duis enim sunt qui ullamco est tempor labore aute aliquip. Sunt eu veniam in amet cillum nisi tempor quis in fugiat culpa exercitation sunt. Exercitation enim dolore sit exercitation in mollit culpa magna amet et amet.\r\n",+    "registered": "2014-05-02T07:58:52 +07:00",+    "latitude": -24.836277,+    "longitude": -108.207588,+    "tags": [+      "aliquip",+      "dolor",+      "velit",+      "non",+      "sint",+      "deserunt",+      "ut"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Maynard Shannon"+      },+      {+        "id": 1,+        "name": "Ernestine Sullivan"+      },+      {+        "id": 2,+        "name": "Sullivan Juarez"+      }+    ],+    "greeting": "Hello, Queen Mckay! You have 8 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a902c9d0c4f7379c125",+    "index": 55,+    "guid": "c13147c1-9aab-432b-9eaa-eda127454f06",+    "isActive": false,+    "balance": "$1,498.79",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "green",+    "name": "Madeline Rhodes",+    "gender": "female",+    "company": "LOCAZONE",+    "email": "madelinerhodes@locazone.com",+    "phone": "+1 (817) 404-2650",+    "address": "648 Rochester Avenue, Tetherow, Arizona, 751",+    "about": "Sit velit ea enim mollit ad fugiat anim commodo minim qui sit dolor aliqua. Amet nostrud aliquip qui velit et ea reprehenderit sint ipsum quis. Ut amet aute enim proident. Et officia nostrud voluptate non tempor quis aliquip ullamco commodo consequat fugiat ut. Eiusmod sit excepteur non nostrud esse consequat nulla sunt deserunt aliqua. Commodo laborum voluptate ea eu non excepteur pariatur.\r\n",+    "registered": "2014-03-14T19:50:42 +07:00",+    "latitude": -31.489199,+    "longitude": 124.798218,+    "tags": [+      "tempor",+      "culpa",+      "pariatur",+      "irure",+      "nisi",+      "proident",+      "quis"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Hebert Kline"+      },+      {+        "id": 1,+        "name": "Daisy Cochran"+      },+      {+        "id": 2,+        "name": "Russell Gilmore"+      }+    ],+    "greeting": "Hello, Madeline Rhodes! You have 10 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90b6d8621dab6c9126",+    "index": 56,+    "guid": "2ebcecc1-180e-46b7-bdca-9d9a6babc687",+    "isActive": false,+    "balance": "$3,190.82",+    "picture": "http://placehold.it/32x32",+    "age": 27,+    "eyeColor": "blue",+    "name": "Rasmussen Knapp",+    "gender": "male",+    "company": "BIOSPAN",+    "email": "rasmussenknapp@biospan.com",+    "phone": "+1 (860) 461-3219",+    "address": "214 Williams Court, Brady, Oregon, 5174",+    "about": "Tempor ullamco officia laborum irure cillum est culpa tempor pariatur aliqua officia incididunt tempor. Laboris adipisicing nostrud Lorem veniam enim consequat mollit nisi. Minim nulla culpa dolor esse dolore deserunt reprehenderit adipisicing aliquip.\r\n",+    "registered": "2014-08-11T17:15:51 +07:00",+    "latitude": -25.850361,+    "longitude": -36.01581,+    "tags": [+      "enim",+      "laboris",+      "dolore",+      "amet",+      "nisi",+      "in",+      "aliqua"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Letha Peters"+      },+      {+        "id": 1,+        "name": "Lavonne Mccarthy"+      },+      {+        "id": 2,+        "name": "Hensley Kim"+      }+    ],+    "greeting": "Hello, Rasmussen Knapp! You have 5 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a902e4d6731ddf406bf",+    "index": 57,+    "guid": "7a13b0b9-7cc4-477a-944f-a27eb7e74ae6",+    "isActive": false,+    "balance": "$1,711.06",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "brown",+    "name": "Maryellen Russell",+    "gender": "female",+    "company": "MAXEMIA",+    "email": "maryellenrussell@maxemia.com",+    "phone": "+1 (839) 590-2573",+    "address": "514 Roosevelt Court, Sugartown, American Samoa, 6602",+    "about": "Pariatur laborum nostrud aliqua nisi cillum sunt laborum cillum minim pariatur et consectetur minim adipisicing. Exercitation non dolor id voluptate aute sint sunt. Nostrud cupidatat officia dolor cupidatat ex irure non. Fugiat laboris quis id aliqua sunt consectetur est ea. Eiusmod mollit enim Lorem cupidatat consectetur anim nostrud enim eu irure. Et eiusmod velit esse fugiat elit laboris labore voluptate ipsum. Excepteur consequat proident quis voluptate excepteur nulla in.\r\n",+    "registered": "2014-05-17T21:19:21 +07:00",+    "latitude": -15.634102,+    "longitude": -81.860909,+    "tags": [+      "ea",+      "ipsum",+      "esse",+      "veniam",+      "reprehenderit",+      "adipisicing",+      "do"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Virgie Whitaker"+      },+      {+        "id": 1,+        "name": "Earlene Ruiz"+      },+      {+        "id": 2,+        "name": "Rosa Estrada"+      }+    ],+    "greeting": "Hello, Maryellen Russell! You have 5 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a906ea1b53a8de569dd",+    "index": 58,+    "guid": "0e91224f-af4a-4cb0-a51e-5874ad140b32",+    "isActive": false,+    "balance": "$1,226.26",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "blue",+    "name": "Wright Morris",+    "gender": "male",+    "company": "APPLICA",+    "email": "wrightmorris@applica.com",+    "phone": "+1 (968) 550-2677",+    "address": "630 Hornell Loop, Sparkill, Montana, 7355",+    "about": "Veniam commodo nostrud nostrud ullamco do aliquip quis dolore laboris culpa minim do est. In sunt consequat irure veniam minim duis ex commodo duis. Ullamco eu reprehenderit dolore eiusmod est exercitation nisi tempor.\r\n",+    "registered": "2014-02-05T10:33:53 +08:00",+    "latitude": -16.050009,+    "longitude": -149.883606,+    "tags": [+      "Lorem",+      "in",+      "est",+      "consequat",+      "cillum",+      "adipisicing",+      "commodo"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Washington Carson"+      },+      {+        "id": 1,+        "name": "Hines Bean"+      },+      {+        "id": 2,+        "name": "Cox Powell"+      }+    ],+    "greeting": "Hello, Wright Morris! You have 7 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a9047deb3b6b5122221",+    "index": 59,+    "guid": "f85bae2d-b72a-4f81-b596-b5338ec41578",+    "isActive": true,+    "balance": "$1,928.94",+    "picture": "http://placehold.it/32x32",+    "age": 26,+    "eyeColor": "brown",+    "name": "Agnes Guzman",+    "gender": "female",+    "company": "PEARLESSA",+    "email": "agnesguzman@pearlessa.com",+    "phone": "+1 (859) 451-3816",+    "address": "874 Duffield Street, Benson, Hawaii, 1388",+    "about": "Ad voluptate incididunt ullamco ullamco velit adipisicing culpa aute minim adipisicing non. Consectetur elit ullamco mollit ipsum aliqua in enim Lorem eiusmod nisi fugiat exercitation. Do amet pariatur deserunt ex labore exercitation non ad commodo aliquip. Nostrud magna ipsum reprehenderit qui consectetur cillum irure nostrud do quis excepteur cillum.\r\n",+    "registered": "2014-07-28T12:22:31 +07:00",+    "latitude": -89.041016,+    "longitude": -4.513498,+    "tags": [+      "eiusmod",+      "deserunt",+      "deserunt",+      "eiusmod",+      "minim",+      "nisi",+      "magna"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Kari Trujillo"+      },+      {+        "id": 1,+        "name": "Kaye Sloan"+      },+      {+        "id": 2,+        "name": "Aguilar Fields"+      }+    ],+    "greeting": "Hello, Agnes Guzman! You have 9 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a905ad56237e1e3ae99",+    "index": 60,+    "guid": "3244774e-3c8d-4c84-8ae6-d04486ce05d7",+    "isActive": false,+    "balance": "$3,045.23",+    "picture": "http://placehold.it/32x32",+    "age": 27,+    "eyeColor": "green",+    "name": "Jill Evans",+    "gender": "female",+    "company": "GOLISTIC",+    "email": "jillevans@golistic.com",+    "phone": "+1 (871) 577-2459",+    "address": "738 Putnam Avenue, Ona, South Dakota, 4749",+    "about": "Irure exercitation esse quis commodo sunt laborum esse id anim. Ut ut ad quis qui id labore ut tempor labore velit laborum pariatur. Dolore ipsum ea tempor excepteur esse cillum sit non eu sit irure adipisicing mollit. Nulla ut proident velit consequat officia magna ex duis proident aliqua amet exercitation do commodo. Nulla Lorem ad reprehenderit mollit deserunt veniam qui duis enim enim consectetur do.\r\n",+    "registered": "2014-05-05T11:50:14 +07:00",+    "latitude": -56.941561,+    "longitude": -169.158104,+    "tags": [+      "consequat",+      "minim",+      "minim",+      "laborum",+      "aute",+      "nisi",+      "aliqua"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Compton Becker"+      },+      {+        "id": 1,+        "name": "Conner Wall"+      },+      {+        "id": 2,+        "name": "Bright Harvey"+      }+    ],+    "greeting": "Hello, Jill Evans! You have 2 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90f530d8bc9e6faf86",+    "index": 61,+    "guid": "a983ed9d-fb1b-48ee-94b7-54b33634ccbc",+    "isActive": false,+    "balance": "$3,091.12",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "brown",+    "name": "Susana Berry",+    "gender": "female",+    "company": "POWERNET",+    "email": "susanaberry@powernet.com",+    "phone": "+1 (879) 454-3173",+    "address": "141 Cambridge Place, Florence, District Of Columbia, 6760",+    "about": "Magna occaecat laborum voluptate excepteur. Proident esse voluptate enim est exercitation elit voluptate minim ex. Velit officia cupidatat sit quis reprehenderit minim voluptate et nulla cupidatat duis mollit. Aute incididunt id magna nostrud cupidatat qui sit. Enim anim enim excepteur est sunt non enim proident sit non deserunt et veniam culpa. Ullamco irure ullamco id esse exercitation anim et fugiat labore. Do enim exercitation deserunt sint consectetur occaecat commodo commodo elit.\r\n",+    "registered": "2014-06-08T14:24:28 +07:00",+    "latitude": 75.590221,+    "longitude": -127.23641,+    "tags": [+      "esse",+      "anim",+      "est",+      "anim",+      "esse",+      "adipisicing",+      "mollit"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Helene Holcomb"+      },+      {+        "id": 1,+        "name": "Kramer Gregory"+      },+      {+        "id": 2,+        "name": "Fitzgerald Graves"+      }+    ],+    "greeting": "Hello, Susana Berry! You have 1 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90e6f9c07f205357ec",+    "index": 62,+    "guid": "26cecce2-1202-4703-8bf5-8ff431336b37",+    "isActive": false,+    "balance": "$3,437.96",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "blue",+    "name": "Weeks Wallace",+    "gender": "male",+    "company": "SUREMAX",+    "email": "weekswallace@suremax.com",+    "phone": "+1 (946) 528-2733",+    "address": "219 Dekalb Avenue, Hasty, North Carolina, 7278",+    "about": "Magna dolor ex dolor eiusmod sint laboris consequat non magna ipsum. Nostrud qui aute ut consectetur in amet deserunt aliqua voluptate. In velit nisi voluptate amet consequat. Tempor deserunt velit ut aliqua duis cupidatat laboris amet in ipsum aliquip adipisicing. Quis anim cillum labore ipsum commodo deserunt mollit tempor tempor pariatur dolore. Irure aute ipsum do occaecat laborum eiusmod ad proident exercitation elit cillum do.\r\n",+    "registered": "2014-07-17T22:33:55 +07:00",+    "latitude": -22.986103,+    "longitude": -110.848014,+    "tags": [+      "ut",+      "irure",+      "elit",+      "quis",+      "ut",+      "fugiat",+      "sunt"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Colon Tyler"+      },+      {+        "id": 1,+        "name": "Dianne Lucas"+      },+      {+        "id": 2,+        "name": "Mathews Acosta"+      }+    ],+    "greeting": "Hello, Weeks Wallace! You have 8 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a9034039bde61fe5fdb",+    "index": 63,+    "guid": "cad69671-eb0a-4128-8024-9a0f469cf1f8",+    "isActive": true,+    "balance": "$2,503.03",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "green",+    "name": "Watson Tucker",+    "gender": "male",+    "company": "IMKAN",+    "email": "watsontucker@imkan.com",+    "phone": "+1 (841) 499-3837",+    "address": "297 Falmouth Street, Woodlands, Tennessee, 2227",+    "about": "Do aliquip laboris voluptate aliqua duis duis qui. Lorem officia consectetur et in nulla do aliquip occaecat labore officia sunt ipsum ad consequat. Culpa voluptate adipisicing dolore do velit ea.\r\n",+    "registered": "2014-09-16T17:39:32 +07:00",+    "latitude": 76.336221,+    "longitude": -154.036452,+    "tags": [+      "veniam",+      "non",+      "aliquip",+      "ex",+      "esse",+      "sint",+      "voluptate"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Lolita Finch"+      },+      {+        "id": 1,+        "name": "Gilmore Solis"+      },+      {+        "id": 2,+        "name": "Faith Gallegos"+      }+    ],+    "greeting": "Hello, Watson Tucker! You have 9 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90780b195513995278",+    "index": 64,+    "guid": "625810dc-6353-4387-862c-e71ed6115966",+    "isActive": false,+    "balance": "$2,428.28",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "green",+    "name": "Levy Ortega",+    "gender": "male",+    "company": "FIBEROX",+    "email": "levyortega@fiberox.com",+    "phone": "+1 (819) 514-2393",+    "address": "485 Dunne Place, Sena, Idaho, 1583",+    "about": "Exercitation reprehenderit voluptate aliqua laborum dolore consequat pariatur ipsum occaecat culpa et dolore voluptate. Laborum ut adipisicing exercitation irure ipsum ea. Occaecat aute officia et qui id elit adipisicing consectetur. Laborum ullamco pariatur eiusmod dolore aliqua ea nostrud. Occaecat ullamco nostrud deserunt ea officia. Deserunt incididunt et laboris veniam laboris adipisicing culpa laborum occaecat culpa sit labore. Irure in ipsum exercitation ea laboris culpa.\r\n",+    "registered": "2014-06-19T01:29:28 +07:00",+    "latitude": -66.489978,+    "longitude": 35.142253,+    "tags": [+      "consequat",+      "ut",+      "ipsum",+      "ullamco",+      "anim",+      "irure",+      "consectetur"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Nellie Webb"+      },+      {+        "id": 1,+        "name": "Sheri Roy"+      },+      {+        "id": 2,+        "name": "Elizabeth Cooke"+      }+    ],+    "greeting": "Hello, Levy Ortega! You have 3 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a901df67d5f687df4ab",+    "index": 65,+    "guid": "73d49a86-1caa-4ef5-b637-aef68b215e96",+    "isActive": true,+    "balance": "$3,990.52",+    "picture": "http://placehold.it/32x32",+    "age": 24,+    "eyeColor": "blue",+    "name": "Webster Conway",+    "gender": "male",+    "company": "PRISMATIC",+    "email": "websterconway@prismatic.com",+    "phone": "+1 (857) 462-3648",+    "address": "557 Dekoven Court, Sandston, Palau, 8537",+    "about": "Fugiat non velit fugiat sint minim magna occaecat deserunt enim adipisicing excepteur amet. Esse incididunt mollit nisi ut id consectetur qui laborum consequat et occaecat. Tempor cupidatat enim sunt cillum. Laborum consequat Lorem enim fugiat id voluptate incididunt aliquip eu esse dolor duis ad. Officia dolore duis nisi veniam ut ut dolore fugiat deserunt aute consectetur. Excepteur voluptate mollit velit duis ullamco voluptate ullamco.\r\n",+    "registered": "2014-04-30T14:39:28 +07:00",+    "latitude": -67.082095,+    "longitude": 38.979656,+    "tags": [+      "amet",+      "aliquip",+      "ea",+      "culpa",+      "incididunt",+      "dolor",+      "fugiat"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Sharp Ramirez"+      },+      {+        "id": 1,+        "name": "Leona Campbell"+      },+      {+        "id": 2,+        "name": "Hyde Reyes"+      }+    ],+    "greeting": "Hello, Webster Conway! You have 3 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90f7b820f93d4df443",+    "index": 66,+    "guid": "1a306b16-3a38-426c-9254-22dd7264c108",+    "isActive": true,+    "balance": "$2,194.31",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "brown",+    "name": "Hill Lancaster",+    "gender": "male",+    "company": "UNIWORLD",+    "email": "hilllancaster@uniworld.com",+    "phone": "+1 (836) 462-3865",+    "address": "786 Dictum Court, Roulette, Minnesota, 3625",+    "about": "Adipisicing ea commodo et nulla ullamco fugiat do magna occaecat consectetur cupidatat nisi fugiat consequat. Velit veniam eu cupidatat adipisicing culpa non non velit amet labore. Dolore dolor enim eiusmod ipsum excepteur non sint ullamco irure laboris nulla id.\r\n",+    "registered": "2014-03-09T12:51:14 +07:00",+    "latitude": -65.924237,+    "longitude": 161.521943,+    "tags": [+      "amet",+      "id",+      "aliquip",+      "aliquip",+      "exercitation",+      "excepteur",+      "cupidatat"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Morrow Mullen"+      },+      {+        "id": 1,+        "name": "Calderon Campos"+      },+      {+        "id": 2,+        "name": "Janis Ramsey"+      }+    ],+    "greeting": "Hello, Hill Lancaster! You have 10 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a906c7f0305536c965c",+    "index": 67,+    "guid": "d1dadd20-7ced-447d-ba72-61e886f4195e",+    "isActive": true,+    "balance": "$3,014.64",+    "picture": "http://placehold.it/32x32",+    "age": 25,+    "eyeColor": "brown",+    "name": "Fletcher Pearson",+    "gender": "male",+    "company": "QOT",+    "email": "fletcherpearson@qot.com",+    "phone": "+1 (930) 439-2213",+    "address": "779 Middagh Street, Crayne, Illinois, 2229",+    "about": "Nulla sit officia velit dolore eiusmod veniam anim laborum Lorem anim et enim irure. Quis labore ad proident occaecat dolore tempor occaecat dolor dolore aliqua laboris esse enim. Dolore tempor cupidatat aute labore aliqua nulla non est.\r\n",+    "registered": "2014-04-25T09:09:10 +07:00",+    "latitude": -2.329892,+    "longitude": 135.411164,+    "tags": [+      "magna",+      "ipsum",+      "tempor",+      "velit",+      "esse",+      "magna",+      "nisi"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Tonya Ashley"+      },+      {+        "id": 1,+        "name": "Latisha Burris"+      },+      {+        "id": 2,+        "name": "Tracey Rowe"+      }+    ],+    "greeting": "Hello, Fletcher Pearson! You have 9 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a9057e5269ab81d8e18",+    "index": 68,+    "guid": "4723bd56-76cb-4a30-bdf5-8b4c4c9805aa",+    "isActive": false,+    "balance": "$3,114.82",+    "picture": "http://placehold.it/32x32",+    "age": 23,+    "eyeColor": "blue",+    "name": "Odessa Lawson",+    "gender": "female",+    "company": "JOVIOLD",+    "email": "odessalawson@joviold.com",+    "phone": "+1 (921) 400-3177",+    "address": "443 Ryder Avenue, Camino, Missouri, 487",+    "about": "Labore aliquip nulla est eiusmod amet Lorem duis fugiat duis do excepteur voluptate in non. Consequat nisi reprehenderit ullamco eu sit id consectetur commodo culpa consequat dolore aliqua. Amet nulla ut in laboris dolor do ad laboris eu commodo qui dolore pariatur. Et qui cillum anim dolore ipsum excepteur id laboris minim dolor.\r\n",+    "registered": "2014-03-26T22:07:14 +07:00",+    "latitude": 18.291259,+    "longitude": -86.22914,+    "tags": [+      "nisi",+      "ut",+      "dolore",+      "ullamco",+      "cupidatat",+      "nulla",+      "laborum"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Vonda Cote"+      },+      {+        "id": 1,+        "name": "Lewis Gonzales"+      },+      {+        "id": 2,+        "name": "Jacqueline Richmond"+      }+    ],+    "greeting": "Hello, Odessa Lawson! You have 4 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90f748a6195f1c2b42",+    "index": 69,+    "guid": "697c2775-d924-436d-ba9f-e21bd4fa0f73",+    "isActive": false,+    "balance": "$1,269.09",+    "picture": "http://placehold.it/32x32",+    "age": 40,+    "eyeColor": "green",+    "name": "Selena Nieves",+    "gender": "female",+    "company": "INTRAWEAR",+    "email": "selenanieves@intrawear.com",+    "phone": "+1 (862) 476-3196",+    "address": "101 Harkness Avenue, Worton, Connecticut, 400",+    "about": "Sunt aliquip exercitation dolor dolore nostrud anim enim anim est officia. Minim ea Lorem ullamco reprehenderit officia reprehenderit ex ex reprehenderit. Qui nulla ullamco consequat minim exercitation. Veniam id eu pariatur ut veniam dolore aliquip qui aliqua incididunt ut.\r\n",+    "registered": "2014-03-07T15:11:53 +08:00",+    "latitude": -43.588256,+    "longitude": 43.731157,+    "tags": [+      "duis",+      "duis",+      "reprehenderit",+      "ad",+      "magna",+      "excepteur",+      "officia"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Rutledge Hines"+      },+      {+        "id": 1,+        "name": "Carrillo Johnson"+      },+      {+        "id": 2,+        "name": "Morgan Parks"+      }+    ],+    "greeting": "Hello, Selena Nieves! You have 9 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90628ac7e339a407a5",+    "index": 70,+    "guid": "6ddd302b-fd62-47f9-aa8a-9fb2c35172c5",+    "isActive": true,+    "balance": "$2,185.43",+    "picture": "http://placehold.it/32x32",+    "age": 34,+    "eyeColor": "blue",+    "name": "Georgia Moran",+    "gender": "female",+    "company": "EARTHMARK",+    "email": "georgiamoran@earthmark.com",+    "phone": "+1 (970) 439-3884",+    "address": "848 Fay Court, Hayes, Maine, 7603",+    "about": "Ea do et excepteur dolor cupidatat nisi. Quis deserunt cupidatat duis enim eu deserunt anim enim. Cillum consectetur occaecat exercitation occaecat duis dolor voluptate officia exercitation irure. Occaecat magna proident enim exercitation veniam. Est commodo ullamco minim esse enim commodo ea commodo nulla et voluptate aliqua anim. Quis magna commodo nulla quis sit duis id et ex id ea dolore anim.\r\n",+    "registered": "2014-04-22T10:10:46 +07:00",+    "latitude": -78.673083,+    "longitude": 167.271688,+    "tags": [+      "non",+      "labore",+      "adipisicing",+      "cupidatat",+      "cupidatat",+      "quis",+      "aliquip"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Andrews Love"+      },+      {+        "id": 1,+        "name": "Brianna Yates"+      },+      {+        "id": 2,+        "name": "Jennifer Bass"+      }+    ],+    "greeting": "Hello, Georgia Moran! You have 10 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a901ec4ee748cbbc125",+    "index": 71,+    "guid": "0e5fc95f-e605-4baa-bc36-b2f795c42e03",+    "isActive": false,+    "balance": "$2,256.63",+    "picture": "http://placehold.it/32x32",+    "age": 22,+    "eyeColor": "blue",+    "name": "House Sargent",+    "gender": "male",+    "company": "FANFARE",+    "email": "housesargent@fanfare.com",+    "phone": "+1 (877) 416-3590",+    "address": "961 Olive Street, Sultana, Puerto Rico, 3764",+    "about": "Cillum minim aliquip sit nulla aute commodo pariatur reprehenderit aliqua laboris in sint velit. Qui irure ut nostrud elit aliqua reprehenderit tempor quis laboris. Voluptate enim eiusmod laborum est excepteur enim est. Veniam non magna ea proident deserunt ipsum Lorem adipisicing velit eiusmod. Culpa id ea non ex ad.\r\n",+    "registered": "2014-04-27T09:04:21 +07:00",+    "latitude": -54.902834,+    "longitude": 147.773359,+    "tags": [+      "cupidatat",+      "voluptate",+      "dolor",+      "excepteur",+      "exercitation",+      "id",+      "in"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Francis Alford"+      },+      {+        "id": 1,+        "name": "Berta Sparks"+      },+      {+        "id": 2,+        "name": "Laura Hahn"+      }+    ],+    "greeting": "Hello, House Sargent! You have 9 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90b51db1c7d287288e",+    "index": 72,+    "guid": "574450df-adad-4071-b642-0971f5f7928e",+    "isActive": true,+    "balance": "$2,263.30",+    "picture": "http://placehold.it/32x32",+    "age": 38,+    "eyeColor": "green",+    "name": "Roseann Lambert",+    "gender": "female",+    "company": "ROUGHIES",+    "email": "roseannlambert@roughies.com",+    "phone": "+1 (908) 551-2196",+    "address": "142 Girard Street, Levant, New Mexico, 2920",+    "about": "Aliquip ea elit anim aliqua in ea. Ex nisi nulla veniam amet. Occaecat pariatur qui consectetur consectetur anim ut anim cillum consectetur adipisicing pariatur. Cillum quis aliquip ad do in fugiat minim et ad labore sit ut aliqua cillum. Elit enim laboris incididunt laboris. Est in ullamco laboris deserunt aliqua veniam. Aute cillum culpa do dolore.\r\n",+    "registered": "2014-04-29T13:57:00 +07:00",+    "latitude": 0.812689,+    "longitude": 127.517728,+    "tags": [+      "veniam",+      "quis",+      "do",+      "aliqua",+      "deserunt",+      "id",+      "ut"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Amelia Dunlap"+      },+      {+        "id": 1,+        "name": "Benson Huff"+      },+      {+        "id": 2,+        "name": "Aimee Fisher"+      }+    ],+    "greeting": "Hello, Roseann Lambert! You have 6 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90285dfadf5a8ab1db",+    "index": 73,+    "guid": "cf2c0b72-e90e-43d1-a5ee-ff85e28272ec",+    "isActive": false,+    "balance": "$3,053.88",+    "picture": "http://placehold.it/32x32",+    "age": 20,+    "eyeColor": "brown",+    "name": "Althea Burgess",+    "gender": "female",+    "company": "RODEMCO",+    "email": "altheaburgess@rodemco.com",+    "phone": "+1 (946) 406-2326",+    "address": "127 Fleet Place, Northridge, Northern Mariana Islands, 2106",+    "about": "Ea aliquip mollit consectetur non sunt. Deserunt adipisicing sint non excepteur veniam. Sunt eu ad Lorem qui laborum labore. Dolor ut esse veniam dolor officia. Minim occaecat labore voluptate exercitation fugiat eu labore non dolor ipsum do magna qui incididunt.\r\n",+    "registered": "2014-03-16T23:19:14 +07:00",+    "latitude": -63.483213,+    "longitude": 118.593144,+    "tags": [+      "amet",+      "veniam",+      "consequat",+      "deserunt",+      "magna",+      "ea",+      "aliqua"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Delacruz Pollard"+      },+      {+        "id": 1,+        "name": "Kelly Washington"+      },+      {+        "id": 2,+        "name": "Irma Freeman"+      }+    ],+    "greeting": "Hello, Althea Burgess! You have 10 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a902435e7e0219ce954",+    "index": 74,+    "guid": "e3079855-52fe-494a-bb64-cf88934d1f84",+    "isActive": false,+    "balance": "$1,615.23",+    "picture": "http://placehold.it/32x32",+    "age": 28,+    "eyeColor": "brown",+    "name": "Ursula French",+    "gender": "female",+    "company": "KLUGGER",+    "email": "ursulafrench@klugger.com",+    "phone": "+1 (803) 454-3759",+    "address": "768 Bancroft Place, Layhill, Mississippi, 3591",+    "about": "Anim proident aliquip non amet. Dolore occaecat non irure cillum excepteur eu officia irure ea enim incididunt. Adipisicing ad esse voluptate duis dolor irure. Non sunt cillum est exercitation labore cillum minim consequat occaecat est aliqua. Ex adipisicing consequat aliqua pariatur est elit deserunt. Proident fugiat aliquip culpa magna ut deserunt incididunt eu enim esse fugiat eu consequat amet. Ad sit do Lorem aliquip enim ea magna.\r\n",+    "registered": "2014-08-01T00:12:36 +07:00",+    "latitude": -31.044528,+    "longitude": -131.432956,+    "tags": [+      "consequat",+      "enim",+      "nisi",+      "cupidatat",+      "est",+      "sint",+      "nostrud"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Mai Hudson"+      },+      {+        "id": 1,+        "name": "Erickson Perkins"+      },+      {+        "id": 2,+        "name": "Cleveland Armstrong"+      }+    ],+    "greeting": "Hello, Ursula French! You have 8 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a906ae58205e4d302e3",+    "index": 75,+    "guid": "f8b68baa-b922-4a5f-9d4a-fa7d9eee543c",+    "isActive": true,+    "balance": "$1,500.61",+    "picture": "http://placehold.it/32x32",+    "age": 29,+    "eyeColor": "blue",+    "name": "Lee Kelley",+    "gender": "male",+    "company": "INQUALA",+    "email": "leekelley@inquala.com",+    "phone": "+1 (947) 551-3499",+    "address": "973 Bayard Street, Orovada, North Dakota, 8499",+    "about": "Ullamco labore fugiat in minim duis duis reprehenderit deserunt eiusmod nostrud cillum laborum. Incididunt occaecat duis esse consectetur voluptate velit pariatur. Pariatur et qui sint anim sunt fugiat ut proident nulla fugiat. Nostrud ea sunt occaecat nulla qui id cupidatat proident ut.\r\n",+    "registered": "2014-11-01T01:18:21 +07:00",+    "latitude": -59.393379,+    "longitude": -110.276914,+    "tags": [+      "sit",+      "magna",+      "in",+      "consequat",+      "excepteur",+      "consequat",+      "Lorem"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Walton Daniels"+      },+      {+        "id": 1,+        "name": "Hammond Robbins"+      },+      {+        "id": 2,+        "name": "Evangelina Chaney"+      }+    ],+    "greeting": "Hello, Lee Kelley! You have 8 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a902a956e2130c70b9c",+    "index": 76,+    "guid": "3f62418d-23f0-4ed2-a76f-51645437223b",+    "isActive": false,+    "balance": "$2,477.19",+    "picture": "http://placehold.it/32x32",+    "age": 28,+    "eyeColor": "green",+    "name": "Miles Poole",+    "gender": "male",+    "company": "YOGASM",+    "email": "milespoole@yogasm.com",+    "phone": "+1 (866) 412-2294",+    "address": "744 Sutton Street, Richford, Vermont, 7668",+    "about": "Nostrud reprehenderit officia officia ex proident sint nulla sint quis duis laborum duis. Anim adipisicing officia officia anim aliquip incididunt culpa duis sint do ullamco ex consectetur. Commodo et tempor eu consequat laboris tempor ipsum magna elit labore consectetur excepteur.\r\n",+    "registered": "2014-07-20T11:37:28 +07:00",+    "latitude": 23.618997,+    "longitude": -80.142779,+    "tags": [+      "magna",+      "exercitation",+      "Lorem",+      "nostrud",+      "pariatur",+      "ut",+      "laborum"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Claudine Gill"+      },+      {+        "id": 1,+        "name": "Huff Kramer"+      },+      {+        "id": 2,+        "name": "Bryan Doyle"+      }+    ],+    "greeting": "Hello, Miles Poole! You have 10 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90357b2420c0dc0895",+    "index": 77,+    "guid": "ef7aa63d-53b9-4e85-ac36-4cfb1afd214a",+    "isActive": true,+    "balance": "$1,105.70",+    "picture": "http://placehold.it/32x32",+    "age": 39,+    "eyeColor": "green",+    "name": "Cohen Clemons",+    "gender": "male",+    "company": "EARBANG",+    "email": "cohenclemons@earbang.com",+    "phone": "+1 (936) 599-3992",+    "address": "952 Paerdegat Avenue, Frizzleburg, Rhode Island, 7905",+    "about": "Consequat exercitation fugiat ut labore. Ad magna sunt dolore magna nulla. Laborum deserunt magna eu incididunt magna occaecat ut sit aliqua nisi culpa dolor ullamco esse. Enim adipisicing proident proident enim qui est ad non. Ex proident sit irure cillum in nostrud veniam amet excepteur voluptate commodo eu eiusmod ullamco.\r\n",+    "registered": "2014-06-15T00:23:03 +07:00",+    "latitude": 78.28454,+    "longitude": 64.170517,+    "tags": [+      "non",+      "ex",+      "sit",+      "ipsum",+      "esse",+      "enim",+      "minim"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Sanchez Wolf"+      },+      {+        "id": 1,+        "name": "Trudy Melendez"+      },+      {+        "id": 2,+        "name": "Magdalena Hatfield"+      }+    ],+    "greeting": "Hello, Cohen Clemons! You have 3 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90ae5beac7dec2ba78",+    "index": 78,+    "guid": "1bccbb43-2801-4c99-a646-001622f3653c",+    "isActive": false,+    "balance": "$1,246.07",+    "picture": "http://placehold.it/32x32",+    "age": 35,+    "eyeColor": "blue",+    "name": "Evelyn Combs",+    "gender": "female",+    "company": "BITENDREX",+    "email": "evelyncombs@bitendrex.com",+    "phone": "+1 (937) 463-3648",+    "address": "498 Beayer Place, Caln, Michigan, 637",+    "about": "Laboris ipsum ea est nisi exercitation adipisicing commodo ea ipsum tempor. Laboris duis sit aliquip reprehenderit id cillum officia. Tempor velit reprehenderit adipisicing dolor ut qui id magna consequat. Fugiat proident sunt sit reprehenderit duis. Eu ipsum adipisicing eu magna cupidatat mollit esse.\r\n",+    "registered": "2014-06-14T20:28:41 +07:00",+    "latitude": 13.771679,+    "longitude": 58.844141,+    "tags": [+      "ex",+      "irure",+      "quis",+      "velit",+      "deserunt",+      "mollit",+      "irure"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Melton Wright"+      },+      {+        "id": 1,+        "name": "Letitia Osborn"+      },+      {+        "id": 2,+        "name": "Delgado Hebert"+      }+    ],+    "greeting": "Hello, Evelyn Combs! You have 7 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90a58e6a9e15665417",+    "index": 79,+    "guid": "6c039c25-e902-4121-9319-aa5e25f09b90",+    "isActive": true,+    "balance": "$1,839.17",+    "picture": "http://placehold.it/32x32",+    "age": 27,+    "eyeColor": "blue",+    "name": "Lakeisha Glover",+    "gender": "female",+    "company": "REALMO",+    "email": "lakeishaglover@realmo.com",+    "phone": "+1 (962) 444-3749",+    "address": "259 Homecrest Court, Villarreal, Oklahoma, 5463",+    "about": "Lorem cupidatat non elit mollit commodo tempor dolore sint qui officia fugiat mollit ex. Ea commodo minim labore commodo commodo sint occaecat eu aute est excepteur labore eiusmod ut. Fugiat voluptate laborum mollit aliqua ea. Ut fugiat culpa do velit non nisi voluptate exercitation. Duis elit velit adipisicing esse.\r\n",+    "registered": "2014-10-07T01:42:52 +07:00",+    "latitude": 7.777536,+    "longitude": -148.148716,+    "tags": [+      "officia",+      "Lorem",+      "eu",+      "eiusmod",+      "mollit",+      "duis",+      "exercitation"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Hodge Snider"+      },+      {+        "id": 1,+        "name": "Maritza Gilliam"+      },+      {+        "id": 2,+        "name": "Barbra Harding"+      }+    ],+    "greeting": "Hello, Lakeisha Glover! You have 5 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a904e60ffa71e64c330",+    "index": 80,+    "guid": "764804ce-2ded-4ab7-aef7-cc638d74a1f6",+    "isActive": true,+    "balance": "$3,096.79",+    "picture": "http://placehold.it/32x32",+    "age": 36,+    "eyeColor": "green",+    "name": "Hall Woodard",+    "gender": "male",+    "company": "HOTCAKES",+    "email": "hallwoodard@hotcakes.com",+    "phone": "+1 (923) 579-2251",+    "address": "678 Johnson Avenue, Nescatunga, West Virginia, 5718",+    "about": "Nulla Lorem proident incididunt nulla amet. Consectetur ea fugiat est adipisicing nisi exercitation ea irure. Id nisi anim culpa incididunt ea laborum. Non est aute anim deserunt ad cupidatat.\r\n",+    "registered": "2014-07-25T16:17:12 +07:00",+    "latitude": -72.300952,+    "longitude": 149.908938,+    "tags": [+      "magna",+      "fugiat",+      "laboris",+      "nulla",+      "tempor",+      "consequat",+      "officia"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Tessa Mccray"+      },+      {+        "id": 1,+        "name": "Hendricks Larson"+      },+      {+        "id": 2,+        "name": "Cecilia Mooney"+      }+    ],+    "greeting": "Hello, Hall Woodard! You have 1 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a9095c0ba3039bba2a0",+    "index": 81,+    "guid": "477bf131-1833-4ceb-a02d-367662e8a0ad",+    "isActive": true,+    "balance": "$3,975.04",+    "picture": "http://placehold.it/32x32",+    "age": 20,+    "eyeColor": "brown",+    "name": "Mccray Holman",+    "gender": "male",+    "company": "NETROPIC",+    "email": "mccrayholman@netropic.com",+    "phone": "+1 (888) 582-2650",+    "address": "930 Alton Place, Stouchsburg, Iowa, 8307",+    "about": "Officia laboris laboris ea magna nulla exercitation ullamco est magna proident cupidatat dolor. Et dolore fugiat nostrud elit in Lorem cillum eu incididunt ullamco irure eiusmod voluptate aliqua. Sint velit veniam nisi in amet incididunt ex et voluptate. Amet laborum sint fugiat nulla dolor adipisicing eiusmod ea. Labore amet nisi et pariatur duis non aliquip ea pariatur sit. Est eu dolore consequat ex quis qui adipisicing minim ea. Proident eiusmod enim irure cillum eu do laborum do voluptate occaecat id consectetur irure dolor.\r\n",+    "registered": "2014-07-15T14:32:20 +07:00",+    "latitude": 69.28999,+    "longitude": 20.24303,+    "tags": [+      "deserunt",+      "labore",+      "voluptate",+      "sint",+      "occaecat",+      "non",+      "sunt"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Ashley Mcintosh"+      },+      {+        "id": 1,+        "name": "Augusta Barr"+      },+      {+        "id": 2,+        "name": "Page Wiley"+      }+    ],+    "greeting": "Hello, Mccray Holman! You have 8 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a908bfd72d2f3594530",+    "index": 82,+    "guid": "e7128ea4-81e3-4888-ba11-4f3670e473ea",+    "isActive": false,+    "balance": "$3,306.06",+    "picture": "http://placehold.it/32x32",+    "age": 22,+    "eyeColor": "green",+    "name": "Sherri Villarreal",+    "gender": "female",+    "company": "TERRAGEN",+    "email": "sherrivillarreal@terragen.com",+    "phone": "+1 (881) 513-2832",+    "address": "922 Surf Avenue, Oberlin, Federated States Of Micronesia, 8301",+    "about": "Occaecat Lorem nostrud sint esse ullamco voluptate cillum sit aliquip sint nostrud. Velit aliqua cupidatat eu adipisicing sunt aute dolore cillum. Voluptate laboris exercitation magna non elit. Excepteur eiusmod enim amet fugiat quis. Anim cillum aute sit magna fugiat ut aliquip incididunt enim.\r\n",+    "registered": "2014-01-29T03:48:07 +08:00",+    "latitude": 70.685812,+    "longitude": -159.885272,+    "tags": [+      "adipisicing",+      "officia",+      "laborum",+      "ipsum",+      "voluptate",+      "sint",+      "cupidatat"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Vinson Berg"+      },+      {+        "id": 1,+        "name": "Emily Strong"+      },+      {+        "id": 2,+        "name": "Lori Gonzalez"+      }+    ],+    "greeting": "Hello, Sherri Villarreal! You have 1 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90ed7615708c5d1f8e",+    "index": 83,+    "guid": "cb7d9a4c-9739-43c8-b75e-0d3cdf462e89",+    "isActive": false,+    "balance": "$3,087.41",+    "picture": "http://placehold.it/32x32",+    "age": 28,+    "eyeColor": "brown",+    "name": "Little Nielsen",+    "gender": "male",+    "company": "LUDAK",+    "email": "littlenielsen@ludak.com",+    "phone": "+1 (826) 557-2684",+    "address": "842 Banner Avenue, Gadsden, Kentucky, 3196",+    "about": "Officia nostrud anim aliqua veniam ut. Non culpa et dolore nostrud elit esse sint mollit anim pariatur id velit irure culpa. Officia irure adipisicing velit velit culpa sunt proident occaecat irure voluptate ullamco. Labore mollit pariatur minim in cillum deserunt. Sint irure ex laborum et minim id ea fugiat excepteur velit veniam velit consequat sint. Culpa anim velit elit officia irure exercitation ex labore est amet. Do do eiusmod ipsum officia veniam laboris irure sint eiusmod non cillum eiusmod.\r\n",+    "registered": "2014-09-19T15:02:29 +07:00",+    "latitude": 26.743234,+    "longitude": -53.174043,+    "tags": [+      "et",+      "sint",+      "culpa",+      "dolore",+      "ea",+      "irure",+      "excepteur"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Gillespie Branch"+      },+      {+        "id": 1,+        "name": "Cantu Kent"+      },+      {+        "id": 2,+        "name": "Nell Meyer"+      }+    ],+    "greeting": "Hello, Little Nielsen! You have 5 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a909137471ca6b126c8",+    "index": 84,+    "guid": "169b0cbf-781c-4b46-8285-e18b3aa6bc0e",+    "isActive": true,+    "balance": "$2,853.96",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "green",+    "name": "Kristi Marquez",+    "gender": "female",+    "company": "RONELON",+    "email": "kristimarquez@ronelon.com",+    "phone": "+1 (838) 414-3765",+    "address": "566 Love Lane, Fresno, New Jersey, 5219",+    "about": "Proident enim commodo ut nisi minim esse eiusmod nisi irure consequat proident voluptate. Culpa ut sunt incididunt sint minim duis excepteur nulla cupidatat ullamco proident nisi ex enim. Qui culpa ex velit do pariatur Lorem dolor ad labore adipisicing magna sunt voluptate dolore. Lorem minim commodo non amet. Nulla reprehenderit consectetur ad nisi voluptate. Ea consectetur deserunt dolore ut. Esse duis consequat reprehenderit cillum commodo consequat ex consectetur do sint velit non deserunt.\r\n",+    "registered": "2014-02-21T07:19:48 +08:00",+    "latitude": 38.750345,+    "longitude": -111.349096,+    "tags": [+      "minim",+      "minim",+      "occaecat",+      "tempor",+      "dolore",+      "fugiat",+      "laborum"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Eddie Soto"+      },+      {+        "id": 1,+        "name": "Valencia Serrano"+      },+      {+        "id": 2,+        "name": "Sears Richards"+      }+    ],+    "greeting": "Hello, Kristi Marquez! You have 3 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90deb8bb21d9c88b7a",+    "index": 85,+    "guid": "58c6180e-8bc6-4ae0-9988-52df23beedac",+    "isActive": false,+    "balance": "$2,028.59",+    "picture": "http://placehold.it/32x32",+    "age": 39,+    "eyeColor": "blue",+    "name": "Callie Sweeney",+    "gender": "female",+    "company": "POLARIA",+    "email": "calliesweeney@polaria.com",+    "phone": "+1 (999) 576-3446",+    "address": "278 Gunnison Court, Wakulla, Nevada, 3605",+    "about": "Minim non eu sint culpa. Non irure ea eiusmod est dolore id culpa laborum ex aliquip et eu. Laborum occaecat labore incididunt et ipsum adipisicing cupidatat eu consectetur reprehenderit quis dolor.\r\n",+    "registered": "2014-11-06T17:55:38 +08:00",+    "latitude": 22.578553,+    "longitude": 70.713617,+    "tags": [+      "veniam",+      "ad",+      "aliqua",+      "id",+      "quis",+      "esse",+      "est"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Cochran Raymond"+      },+      {+        "id": 1,+        "name": "Perry Pugh"+      },+      {+        "id": 2,+        "name": "Walsh Cummings"+      }+    ],+    "greeting": "Hello, Callie Sweeney! You have 8 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a9092b4caeee42e4083",+    "index": 86,+    "guid": "b37a99a1-89ea-4257-bd5c-f8070c6e5d72",+    "isActive": false,+    "balance": "$2,333.35",+    "picture": "http://placehold.it/32x32",+    "age": 27,+    "eyeColor": "brown",+    "name": "Henson Parrish",+    "gender": "male",+    "company": "MANTRO",+    "email": "hensonparrish@mantro.com",+    "phone": "+1 (983) 409-3702",+    "address": "749 Malbone Street, Century, California, 6571",+    "about": "Pariatur nisi magna laboris ipsum ad sint. Exercitation sit id reprehenderit fugiat ea dolor. Duis exercitation voluptate nulla duis enim culpa eiusmod nulla mollit et occaecat eu Lorem.\r\n",+    "registered": "2014-06-21T02:15:00 +07:00",+    "latitude": 42.27087,+    "longitude": 88.230275,+    "tags": [+      "sunt",+      "excepteur",+      "veniam",+      "cillum",+      "sunt",+      "consequat",+      "ullamco"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Dunn Cantrell"+      },+      {+        "id": 1,+        "name": "Mendoza Keller"+      },+      {+        "id": 2,+        "name": "Josefa Green"+      }+    ],+    "greeting": "Hello, Henson Parrish! You have 7 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a9001009b488b9deadf",+    "index": 87,+    "guid": "4a8e033a-6160-44a0-b6f6-e07f11455db9",+    "isActive": false,+    "balance": "$2,886.19",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "blue",+    "name": "Mcgowan Hogan",+    "gender": "male",+    "company": "MAGNEMO",+    "email": "mcgowanhogan@magnemo.com",+    "phone": "+1 (816) 507-2353",+    "address": "979 Reed Street, Roberts, Maryland, 9773",+    "about": "Sunt sint labore aliqua nisi ipsum mollit. Lorem aliquip nisi Lorem eu velit. Laborum reprehenderit minim cillum culpa cupidatat commodo do aute dolore. Sunt ullamco consectetur ex officia anim fugiat quis fugiat laboris est quis officia aliqua pariatur. Adipisicing nulla culpa officia ut reprehenderit ea cupidatat.\r\n",+    "registered": "2014-05-26T12:57:18 +07:00",+    "latitude": -24.348796,+    "longitude": 25.886101,+    "tags": [+      "ex",+      "ullamco",+      "non",+      "ea",+      "enim",+      "quis",+      "ipsum"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Terry Burton"+      },+      {+        "id": 1,+        "name": "Cara Estes"+      },+      {+        "id": 2,+        "name": "Johanna Dillard"+      }+    ],+    "greeting": "Hello, Mcgowan Hogan! You have 1 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a9021cae47006152c91",+    "index": 88,+    "guid": "ebae8f41-1ba7-4f91-8d61-1a1a0d6b515f",+    "isActive": false,+    "balance": "$2,168.49",+    "picture": "http://placehold.it/32x32",+    "age": 25,+    "eyeColor": "brown",+    "name": "Riddle Alvarado",+    "gender": "male",+    "company": "INTERLOO",+    "email": "riddlealvarado@interloo.com",+    "phone": "+1 (892) 530-2012",+    "address": "488 Loring Avenue, Homeworth, Washington, 8337",+    "about": "Officia labore commodo eu consectetur. Consectetur consequat voluptate minim dolor do anim magna deserunt ullamco. Mollit laborum eiusmod veniam velit officia dolore dolore in ex veniam officia eu elit fugiat. Labore non in Lorem nulla irure ea id cupidatat eu consectetur. Tempor non quis eu nulla aliquip proident elit commodo duis laboris laborum eu amet occaecat.\r\n",+    "registered": "2014-11-13T11:12:08 +08:00",+    "latitude": 21.377099,+    "longitude": 128.211659,+    "tags": [+      "ex",+      "excepteur",+      "magna",+      "enim",+      "magna",+      "et",+      "incididunt"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Elisa Vinson"+      },+      {+        "id": 1,+        "name": "Peterson Reynolds"+      },+      {+        "id": 2,+        "name": "Mason Odonnell"+      }+    ],+    "greeting": "Hello, Riddle Alvarado! You have 1 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a901459251e4d519953",+    "index": 89,+    "guid": "6fe0652a-7055-47d0-8b6a-8bc3b3f6a7d0",+    "isActive": true,+    "balance": "$1,638.04",+    "picture": "http://placehold.it/32x32",+    "age": 29,+    "eyeColor": "blue",+    "name": "Stone Maynard",+    "gender": "male",+    "company": "CONJURICA",+    "email": "stonemaynard@conjurica.com",+    "phone": "+1 (827) 532-2021",+    "address": "631 Orient Avenue, Homestead, Utah, 8151",+    "about": "In voluptate voluptate veniam reprehenderit dolor est ut est voluptate dolore occaecat voluptate. Laboris cillum ex aliquip quis dolor qui qui fugiat sit. Veniam magna dolor mollit sint laborum duis id duis aliqua dolore reprehenderit qui et. Irure cupidatat ea sunt anim amet mollit adipisicing id sint deserunt veniam irure. Reprehenderit elit mollit do ex reprehenderit ipsum aliqua qui. Ea non eiusmod officia laboris dolor tempor deserunt elit velit ex aliqua. Duis reprehenderit duis duis elit irure elit dolore dolore.\r\n",+    "registered": "2014-05-26T12:55:16 +07:00",+    "latitude": -20.476755,+    "longitude": 76.876321,+    "tags": [+      "fugiat",+      "dolore",+      "consequat",+      "do",+      "esse",+      "consectetur",+      "anim"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Mckenzie Bartlett"+      },+      {+        "id": 1,+        "name": "Villarreal Welch"+      },+      {+        "id": 2,+        "name": "Amparo Kelly"+      }+    ],+    "greeting": "Hello, Stone Maynard! You have 5 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a9015625be6710ded3e",+    "index": 90,+    "guid": "d079e795-b71e-446b-91f8-6347ca0e2e57",+    "isActive": false,+    "balance": "$1,156.54",+    "picture": "http://placehold.it/32x32",+    "age": 28,+    "eyeColor": "blue",+    "name": "Baird Jones",+    "gender": "male",+    "company": "KNEEDLES",+    "email": "bairdjones@kneedles.com",+    "phone": "+1 (898) 574-3748",+    "address": "890 Lancaster Avenue, Falconaire, Wisconsin, 9406",+    "about": "Officia veniam sunt minim ex tempor labore consequat laborum adipisicing officia. Incididunt enim excepteur anim et do cupidatat magna excepteur culpa. Dolore enim ea excepteur non commodo aliqua nostrud commodo exercitation dolor duis. Consectetur consequat ullamco in esse fugiat pariatur anim mollit aliqua aliquip qui. Voluptate cupidatat ipsum labore aliquip fugiat cillum amet sunt voluptate occaecat occaecat nostrud.\r\n",+    "registered": "2014-01-22T19:38:09 +08:00",+    "latitude": -30.096555,+    "longitude": -119.933566,+    "tags": [+      "occaecat",+      "qui",+      "enim",+      "in",+      "pariatur",+      "irure",+      "officia"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Gail Flynn"+      },+      {+        "id": 1,+        "name": "Sanford Harmon"+      },+      {+        "id": 2,+        "name": "Noble Chambers"+      }+    ],+    "greeting": "Hello, Baird Jones! You have 3 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a90b147f5343b9ce16b",+    "index": 91,+    "guid": "af036dfd-72dd-451e-b93d-6dceea4796c4",+    "isActive": false,+    "balance": "$3,703.12",+    "picture": "http://placehold.it/32x32",+    "age": 33,+    "eyeColor": "blue",+    "name": "Leila Gay",+    "gender": "female",+    "company": "ZOXY",+    "email": "leilagay@zoxy.com",+    "phone": "+1 (845) 467-2535",+    "address": "800 Little Street, Troy, Louisiana, 233",+    "about": "Ea aliqua excepteur duis est velit eiusmod irure est eiusmod non elit. Consequat nostrud elit ullamco minim labore deserunt commodo. Mollit amet duis laboris mollit est ex aliquip. Minim et veniam reprehenderit voluptate aliqua id officia excepteur consequat fugiat non ex eu. Fugiat officia cupidatat pariatur voluptate excepteur in.\r\n",+    "registered": "2014-08-02T18:50:58 +07:00",+    "latitude": 59.481938,+    "longitude": 141.038749,+    "tags": [+      "ipsum",+      "commodo",+      "velit",+      "sit",+      "aliquip",+      "ullamco",+      "nisi"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Conway Summers"+      },+      {+        "id": 1,+        "name": "Deirdre Moody"+      },+      {+        "id": 2,+        "name": "Curtis Dickerson"+      }+    ],+    "greeting": "Hello, Leila Gay! You have 10 unread messages.",+    "favoriteFruit": "apple"+  },+  {+    "_id": "54727a90ffed9e529a6fa6b2",+    "index": 92,+    "guid": "7deb0cd2-5374-40c4-a38d-060ef674b2df",+    "isActive": true,+    "balance": "$2,980.94",+    "picture": "http://placehold.it/32x32",+    "age": 20,+    "eyeColor": "brown",+    "name": "Alma England",+    "gender": "female",+    "company": "SOLAREN",+    "email": "almaengland@solaren.com",+    "phone": "+1 (941) 595-3246",+    "address": "727 Covert Street, Nutrioso, Florida, 9152",+    "about": "Commodo quis occaecat voluptate tempor commodo non ipsum quis tempor pariatur elit. Ea fugiat velit dolor ea et occaecat eu ad aute ipsum. In sunt ad reprehenderit duis. Qui deserunt voluptate proident eu officia laborum pariatur incididunt id nisi. Eiusmod adipisicing do pariatur et incididunt aliquip consectetur.\r\n",+    "registered": "2014-08-08T20:51:29 +07:00",+    "latitude": 70.990007,+    "longitude": -119.193428,+    "tags": [+      "irure",+      "cillum",+      "incididunt",+      "nisi",+      "magna",+      "ullamco",+      "ex"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Downs Keith"+      },+      {+        "id": 1,+        "name": "Dawn Velazquez"+      },+      {+        "id": 2,+        "name": "Deanna Simpson"+      }+    ],+    "greeting": "Hello, Alma England! You have 9 unread messages.",+    "favoriteFruit": "strawberry"+  },+  {+    "_id": "54727a9075e4734b622a166a",+    "index": 93,+    "guid": "c0adc5f1-039a-4b52-a8cf-0196f3c23129",+    "isActive": true,+    "balance": "$2,658.69",+    "picture": "http://placehold.it/32x32",+    "age": 21,+    "eyeColor": "brown",+    "name": "Lou Rose",+    "gender": "female",+    "company": "INFOTRIPS",+    "email": "lourose@infotrips.com",+    "phone": "+1 (845) 564-3943",+    "address": "343 Krier Place, Evergreen, Indiana, 5249",+    "about": "Tempor ullamco id reprehenderit sunt veniam incididunt laboris. Ea ut officia do velit dolor officia Lorem consectetur nisi velit nisi. Aliquip dolore minim sint deserunt deserunt est.\r\n",+    "registered": "2014-04-22T07:46:26 +07:00",+    "latitude": 12.216368,+    "longitude": 8.875707,+    "tags": [+      "velit",+      "consectetur",+      "Lorem",+      "est",+      "adipisicing",+      "ad",+      "ullamco"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Coleen Foley"+      },+      {+        "id": 1,+        "name": "Boone Fitzpatrick"+      },+      {+        "id": 2,+        "name": "Elise Osborne"+      }+    ],+    "greeting": "Hello, Lou Rose! You have 5 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a90512b4f65287789e9",+    "index": 94,+    "guid": "26d470db-29c3-4c14-894b-5654462385a5",+    "isActive": false,+    "balance": "$2,751.47",+    "picture": "http://placehold.it/32x32",+    "age": 23,+    "eyeColor": "blue",+    "name": "Velez Wong",+    "gender": "male",+    "company": "FRANSCENE",+    "email": "velezwong@franscene.com",+    "phone": "+1 (821) 577-3492",+    "address": "197 Huron Street, Hilltop, New Hampshire, 6969",+    "about": "Minim id ullamco ullamco do proident Lorem commodo tempor ea. Est ut id non proident eiusmod. Deserunt fugiat enim culpa veniam sint.\r\n",+    "registered": "2014-07-21T05:23:01 +07:00",+    "latitude": -37.262537,+    "longitude": 132.661281,+    "tags": [+      "culpa",+      "non",+      "elit",+      "nulla",+      "laboris",+      "elit",+      "ex"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Charmaine Curry"+      },+      {+        "id": 1,+        "name": "Clara Randall"+      },+      {+        "id": 2,+        "name": "Lauren Jacobs"+      }+    ],+    "greeting": "Hello, Velez Wong! You have 4 unread messages.",+    "favoriteFruit": "banana"+  },+  {+    "_id": "54727a9095dc4743a5a84bd7",+    "index": 95,+    "guid": "1d1b9166-affc-4d15-ab60-b2edc51f29b4",+    "isActive": true,+    "balance": "$1,063.39",+    "picture": "http://placehold.it/32x32",+    "age": 22,+    "eyeColor": "brown",+    "name": "Catalina Baxter",+    "gender": "female",+    "company": "GAZAK",+    "email": "catalinabaxter@gazak.com",+    "phone": "+1 (839) 435-3437",+    "address": "904 Miller Avenue, Callaghan, Kansas, 7896",+    "about": "Ut ex exercitation commodo sint sint ipsum ea incididunt. Sunt nostrud tempor sint occaecat qui laborum culpa ipsum ullamco veniam est excepteur nostrud. Consequat occaecat id adipisicing esse culpa occaecat. Proident veniam laboris aute minim dolore eiusmod nulla minim elit sint.\r\n",+    "registered": "2014-05-02T10:13:41 +07:00",+    "latitude": 18.545597,+    "longitude": -99.991313,+    "tags": [+      "do",+      "proident",+      "reprehenderit",+      "minim",+      "cillum",+      "quis",+      "esse"+    ],+    "friends": [+      {+        "id": 0,+        "name": "Monique Wilcox"+      },+      {+        "id": 1,+        "name": "Hilda Craig"+      },+      {+        "id": 2,+        "name": "Leola Higgins"+      }+    ],+    "greeting": "Hello, Catalina Baxter! You have 10 unread messages.",+    "favoriteFruit": "apple"+  }+]
+ test/json-data/dates-fract.json view
@@ -0,0 +1,1 @@+["2015-02-02T09:10:11.123Z","2015-02-03T09:10:11.000+0000","2014-01-02T09:10:11.333Z","2014-01-03T02:09:12.000-02:00","2013-05-06T07:08:09.444Z","2015-02-02T09:10:11.66+03:00","2015-02-03T09:10:11.66Z","2014-01-02T09:10:11.66-1200","2014-01-03T02:09:12.66Z","2013-05-06T07:08:09.66+00:00"]
+ test/json-data/dates.json view
@@ -0,0 +1,1 @@+["2015-02-02T09:10:11Z","2015-02-03T09:10:11+0000","2014-01-02T09:10:11Z","2014-01-03T02:09:12-0300","2013-05-06T07:08:09Z","2015-02-02T09:10:11+04:00","2015-02-03T09:10:11Z","2014-01-02T09:10:11-11:45","2014-01-03T02:09:12Z","2013-05-06T07:08:09+0000"]
+ test/json-data/example.json view
@@ -0,0 +1,88 @@+{"web-app": {+  "servlet": [   +    {+      "servlet-name": "cofaxCDS",+      "servlet-class": "org.cofax.cds.CDSServlet",+      "init-param": {+        "configGlossary:installationAt": "Philadelphia, PA",+        "configGlossary:adminEmail": "ksm@pobox.com",+        "configGlossary:poweredBy": "Cofax",+        "configGlossary:poweredByIcon": "/images/cofax.gif",+        "configGlossary:staticPath": "/content/static",+        "templateProcessorClass": "org.cofax.WysiwygTemplate",+        "templateLoaderClass": "org.cofax.FilesTemplateLoader",+        "templatePath": "templates",+        "templateOverridePath": "",+        "defaultListTemplate": "listTemplate.htm",+        "defaultFileTemplate": "articleTemplate.htm",+        "useJSP": false,+        "jspListTemplate": "listTemplate.jsp",+        "jspFileTemplate": "articleTemplate.jsp",+        "cachePackageTagsTrack": 200,+        "cachePackageTagsStore": 200,+        "cachePackageTagsRefresh": 60,+        "cacheTemplatesTrack": 100,+        "cacheTemplatesStore": 50,+        "cacheTemplatesRefresh": 15,+        "cachePagesTrack": 200,+        "cachePagesStore": 100,+        "cachePagesRefresh": 10,+        "cachePagesDirtyRead": 10,+        "searchEngineListTemplate": "forSearchEnginesList.htm",+        "searchEngineFileTemplate": "forSearchEngines.htm",+        "searchEngineRobotsDb": "WEB-INF/robots.db",+        "useDataStore": true,+        "dataStoreClass": "org.cofax.SqlDataStore",+        "redirectionClass": "org.cofax.SqlRedirection",+        "dataStoreName": "cofax",+        "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",+        "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",+        "dataStoreUser": "sa",+        "dataStorePassword": "dataStoreTestQuery",+        "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",+        "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",+        "dataStoreInitConns": 10,+        "dataStoreMaxConns": 100,+        "dataStoreConnUsageLimit": 100,+        "dataStoreLogLevel": "debug",+        "maxUrlLength": 500}},+    {+      "servlet-name": "cofaxEmail",+      "servlet-class": "org.cofax.cds.EmailServlet",+      "init-param": {+      "mailHost": "mail1",+      "mailHostOverride": "mail2"}},+    {+      "servlet-name": "cofaxAdmin",+      "servlet-class": "org.cofax.cds.AdminServlet"},+ +    {+      "servlet-name": "fileServlet",+      "servlet-class": "org.cofax.cds.FileServlet"},+    {+      "servlet-name": "cofaxTools",+      "servlet-class": "org.cofax.cms.CofaxToolsServlet",+      "init-param": {+        "templatePath": "toolstemplates/",+        "log": 1,+        "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",+        "logMaxSize": "",+        "dataLog": 1,+        "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",+        "dataLogMaxSize": "",+        "removePageCache": "/content/admin/remove?cache=pages&id=",+        "removeTemplateCache": "/content/admin/remove?cache=templates&id=",+        "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",+        "lookInContext": 1,+        "adminGroupID": 4,+        "betaServer": true}}],+  "servlet-mapping": {+    "cofaxCDS": "/",+    "cofaxEmail": "/cofaxutil/aemail/*",+    "cofaxAdmin": "/admin/*",+    "fileServlet": "/static/*",+    "cofaxTools": "/tools/*"},+ +  "taglib": {+    "taglib-uri": "cofax.tld",+    "taglib-location": "/WEB-INF/tlds/cofax.tld"}}}
+ test/json-data/geometry.json view
@@ -0,0 +1,1 @@+{"geometry": {"type": "Polygon", "coordinates": [[[-0.939359853061118, 51.57401065198471], [-0.939440892477492, 51.57431080772057], [-0.939543636564569, 51.57460846194951], [-0.939564627628489, 51.574822653966265], [-0.939763179055758, 51.575406210178826], [-0.939787182642249, 51.575552991614], [-0.939819571231525, 51.57564949527348], [-0.939851290904264, 51.57571272360808], [-0.939975682132949, 51.57588648747347], [-0.940036822193859, 51.57598774653439], [-0.940072640734852, 51.57606090267849], [-0.940109693338918, 51.576205104339515], [-0.940125502187331, 51.57645611534466], [-0.940118623499009, 51.57662779459441], [-0.94008851367835, 51.57680555827417], [-0.939998015208524, 51.57709787034017], [-0.939928028667517, 51.577252794653916], [-0.939830628174189, 51.57740747134858], [-0.939796941313687, 51.57749078985784], [-0.939785586773343, 51.57754463746666], [-0.939770656147318, 51.57769016804059], [-0.939658154074368, 51.57824573765943], [-0.939485738834128, 51.57883313597966], [-0.93945717030888, 51.579192545519916], [-0.939524336079755, 51.57928306919007], [-0.939540939284811, 51.57931379092206], [-0.939553921057406, 51.579748206813974], [-0.939549110634237, 51.57983088690364], [-0.939520940649101, 51.58004913048237], [-0.93951863934971, 51.58014801827346], [-0.939525037302583, 51.580245186310094], [-0.939540364690294, 51.58033074581249], [-0.939561798495469, 51.58040197377017], [-0.939594984852117, 51.58046431619436], [-0.939708262827559, 51.580619996404984], [-0.939729069878358, 51.58065615108302], [-0.939759224390201, 51.58072476025555], [-0.939813615319267, 51.58093026195459], [-0.939900523550716, 51.58172321441459], [-0.939894144544868, 51.581997403240464], [-0.939910832471369, 51.58208657162566], [-0.940114353648015, 51.582457967531546], [-0.94022333049887, 51.58267475179605], [-0.940267247821581, 51.58277225843995], [-0.94038427828014, 51.583077233742756], [-0.940493362377966, 51.583289522851196], [-0.940571515796737, 51.58340442254201], [-0.940725857371931, 51.58359464061899], [-0.941198340240742, 51.584069167875626], [-0.941335307610427, 51.584261925920295], [-0.941372786463165, 51.5843261048293], [-0.941416540699353, 51.58443080287741], [-0.941461326187118, 51.584739621364996], [-0.941517445876004, 51.5849954910945], [-0.941575869597484, 51.58533860085252], [-0.941574762730556, 51.58538624677686], [-0.941565185406358, 51.58542572382202], [-0.941550002863301, 51.58545795698674], [-0.941515976834126, 51.58549361692739], [-0.941470510606583, 51.585524677868065], [-0.941423872780384, 51.585544039043356], [-0.94131509921043, 51.585566436558274], [-0.941075026707647, 51.58558675057684], [-0.940953181611661, 51.58561262652464], [-0.940734943851404, 51.58568708689612], [-0.940229533088359, 51.585883040066975], [-0.940067635923264, 51.58595531027499], [-0.939917220191166, 51.58603038143916], [-0.939797255285709, 51.586099433232604], [-0.939675637701456, 51.586177461657186], [-0.939611074554604, 51.58622273608784], [-0.939340396866166, 51.586441486256], [-0.93912244296424, 51.58662744303347], [-0.938817233975319, 51.58671729893312], [-0.938661522913105, 51.586771639765516], [-0.938087678078033, 51.586992141762096], [-0.937332636663603, 51.5873072119485], [-0.93492634290483, 51.58836081134952], [-0.934774110277819, 51.58845114531925], [-0.934663126573178, 51.588505886685766], [-0.934565467487243, 51.588546362183585], [-0.934462140700832, 51.588582290320545], [-0.934337145222589, 51.58861892084846], [-0.934213782000904, 51.588647473549656], [-0.934055887760941, 51.588671216763295], [-0.933259701136762, 51.58864510257983], [-0.933213278816969, 51.588716614209304], [-0.932681740160827, 51.588792708227174], [-0.931992471253759, 51.58900853446031], [-0.930629113767652, 51.58946908647644], [-0.928525036745892, 51.59005953842682], [-0.928533690860491, 51.59024394687689], [-0.928456010745829, 51.59047792078815], [-0.928256501298223, 51.5906748158337], [-0.927916132025856, 51.59066181734799], [-0.927671608556404, 51.590624516635486], [-0.927319567022116, 51.59061680481465], [-0.926850285435352, 51.59062240702726], [-0.926313746570405, 51.59066425819173], [-0.925516790702947, 51.59079184232522], [-0.925387133168341, 51.59078076476673], [-0.925293323156809, 51.59077990606886], [-0.925202187496562, 51.59078806346173], [-0.925112304116411, 51.59080432476366], [-0.925036768134577, 51.59082431403807], [-0.924968299737815, 51.59085066215826], [-0.924899640304234, 51.59088510100373], [-0.924851228495836, 51.590917926896914], [-0.924734051019008, 51.59105082982951], [-0.924694255912291, 51.59108553291224], [-0.924446018071168, 51.59126668934789], [-0.924204972773907, 51.59150995377465], [-0.923492520665307, 51.59215352189589], [-0.922775141969353, 51.59288246146081], [-0.922298613651092, 51.59343737077436], [-0.922101568270595, 51.59365046303728], [-0.92149319027045, 51.59422483935332], [-0.921029930136652, 51.59464499018023], [-0.919455791303858, 51.595519790418045], [-0.919908472816787, 51.59560757835559], [-0.919902358174605, 51.595621908790214], [-0.919721503870405, 51.59588190272939], [-0.919513222918683, 51.59614164398608], [-0.919057326435374, 51.59661490568889], [-0.918991959815932, 51.59669253146064], [-0.918853979663433, 51.59690975873926], [-0.91882720841051, 51.59694278142396], [-0.918711889332325, 51.597056812913756], [-0.918614808732714, 51.59713234806153], [-0.918297245740306, 51.59749448485627], [-0.918073703114389, 51.59778825130676], [-0.917853804369843, 51.59811082427763], [-0.917772408698363, 51.59831598343439], [-0.917709563771812, 51.59853030520902], [-0.917692745480418, 51.59856971355161], [-0.917634249201942, 51.59866178857289], [-0.917443039919903, 51.59887043094418], [-0.917335250471836, 51.598971042984616], [-0.916888284039272, 51.599309503426845], [-0.916921110547038, 51.59938623548714], [-0.916942485633783, 51.5995195094582], [-0.916937652924948, 51.599601289122916], [-0.916945811778801, 51.599683188627004], [-0.916964246289877, 51.599757989575366], [-0.917049297107238, 51.59994580090974], [-0.917089705367533, 51.60000731699611], [-0.917171120773417, 51.60010517795964], [-0.91752823274465, 51.60044925531009], [-0.917834023417531, 51.600765883511485], [-0.917913079603466, 51.600902386385464], [-0.918033251654948, 51.60107073894696], [-0.91851090277833, 51.601507638962644], [-0.918694916056997, 51.601663091331545], [-0.919167224655989, 51.60214309940451], [-0.919302231291783, 51.6024167896932], [-0.919552009673002, 51.60266096432073], [-0.919812571846437, 51.60293760761218], [-0.920091738726093, 51.60358667644501], [-0.920208566517809, 51.603592246724574], [-0.920644522919282, 51.60359715428394], [-0.921093152621479, 51.6036156641763], [-0.921168285587618, 51.603613657034074], [-0.921469264587163, 51.6035867495928], [-0.921584776688781, 51.603586911416876], [-0.921718864440287, 51.603595336217005], [-0.921999521996191, 51.60363387995426], [-0.922136050325758, 51.603661209181794], [-0.922248015684399, 51.60368921195661], [-0.922346882036963, 51.60372159023333], [-0.922478548042792, 51.60377135359644], [-0.922605777045377, 51.603825571929555], [-0.92269948345521, 51.60389297005248], [-0.922855181916126, 51.60396453348124], [-0.922908065211369, 51.60398749776935], [-0.923525984356841, 51.604174796116844], [-0.923689774691443, 51.6042095667925], [-0.923842334751645, 51.60423074681459], [-0.924020987014581, 51.604247669912816], [-0.924152253615336, 51.604253368572344], [-0.924379056519158, 51.60424915231234], [-0.924491916632975, 51.60423939614583], [-0.925129396784027, 51.604149022807746], [-0.925308707040747, 51.60413807581467], [-0.925396812395019, 51.604137083863186], [-0.925816640142735, 51.60415261457396], [-0.926339243350925, 51.604157394450915], [-0.926627592983669, 51.60417621577326], [-0.928219342008724, 51.60433911850777], [-0.928540897883304, 51.60435823822504], [-0.928666454251138, 51.6043611822271], [-0.928925123731038, 51.60435275210506], [-0.929272427371303, 51.60432085222454], [-0.929350681081097, 51.604308977474346], [-0.929525019586135, 51.60426381040009], [-0.929730308556221, 51.60419195021111], [-0.929806393059037, 51.60414948374236], [-0.929854111423592, 51.60408517871234], [-0.929877477717563, 51.604012559228565], [-0.929880189120251, 51.60395863398061], [-0.930157001898001, 51.603362311928585], [-0.930233415197893, 51.60324431822904], [-0.930397156019029, 51.60303540508514], [-0.93058677482955, 51.602831223239896], [-0.930747612253953, 51.60268432562219], [-0.931065151604954, 51.602443542878724], [-0.931358556224333, 51.60224659876122], [-0.931494751600125, 51.602165114969594], [-0.931807666849096, 51.601998019766675], [-0.932115553298882, 51.60186055047904], [-0.932344261944379, 51.601774512081256], [-0.932581062209752, 51.601712824287226], [-0.932837650566022, 51.60166929919289], [-0.93304760157037, 51.60164423223924], [-0.933247236692325, 51.60162806284857], [-0.933524572231589, 51.601623388892406], [-0.93367307135076, 51.60163283011416], [-0.933854562367985, 51.601651562386515], [-0.934222940436163, 51.60170526005669], [-0.934582321335698, 51.60177326158339], [-0.935176916778695, 51.60190903449902], [-0.935323237909383, 51.60194992468383], [-0.935449328012611, 51.60199153042619], [-0.935555166022244, 51.60203475076641], [-0.935754957696255, 51.60213547009268], [-0.935920944220561, 51.60219991608389], [-0.936105992086264, 51.60225194623237], [-0.936251123590137, 51.60228203448254], [-0.9362553703842, 51.602285669620606], [-0.935954861941404, 51.603034649313756], [-0.936025513047831, 51.60328615677915], [-0.937604653681525, 51.60374194595848], [-0.937842729718605, 51.6037494948452], [-0.937998245297976, 51.60376798569096], [-0.938149157504488, 51.60379812385097], [-0.938282536474463, 51.60383709493093], [-0.938398403200176, 51.60388400001471], [-0.938549544157173, 51.60396629131982], [-0.938542113846477, 51.60403725821696], [-0.938540670189083, 51.60403724516617], [-0.938690470772444, 51.60417707075241], [-0.93885671831091, 51.60429276731543], [-0.938949655717409, 51.60433227129961], [-0.939171393952754, 51.60435945147724], [-0.939491406642938, 51.60438302306183], [-0.939580914110842, 51.60438383145672], [-0.939698081584302, 51.604374998744255], [-0.939860253923854, 51.60435578228165], [-0.940131370864495, 51.60430877574863], [-0.940224037565311, 51.60429792302206], [-0.941065905352937, 51.604358569226044], [-0.941456261791824, 51.60439985396626], [-0.94172260946072, 51.604433725629356], [-0.942065117075164, 51.604483568721975], [-0.942405972956444, 51.60454238758566], [-0.942542307804962, 51.60457868292929], [-0.942668453620936, 51.60461848302318], [-0.942754322773386, 51.60465162617505], [-0.942930037674105, 51.6047332338937], [-0.94300827141212, 51.60478429141865], [-0.943050642772121, 51.60482513526179], [-0.943095505071305, 51.604883085645305], [-0.943175837511794, 51.60503037259752], [-0.943199044776033, 51.60508812802956], [-0.943264927978451, 51.605360268787045], [-0.94328295289835, 51.6055168856955], [-0.943285556153251, 51.605653582182974], [-0.94327790338372, 51.60573443814757], [-0.943262026480571, 51.60579633763445], [-0.943228365851772, 51.605877858692274], [-0.943092212068021, 51.60614458434088], [-0.943074097962666, 51.60624063192375], [-0.943061365824471, 51.606415854446915], [-0.943044862244347, 51.60650472320056], [-0.943017897594943, 51.606608783583646], [-0.942979591589439, 51.606703750216774], [-0.942905884027612, 51.60683076806164], [-0.942741267849139, 51.60707925374213], [-0.942655006715899, 51.607249318295594], [-0.942630361430127, 51.60731563455148], [-0.942616263944651, 51.607425205688976], [-0.942621958529523, 51.60749089598715], [-0.942636336634899, 51.60755576531453], [-0.942660904708633, 51.607617129739225], [-0.942696981288364, 51.607680396114986], [-0.942747433102709, 51.60774648940761], [-0.942856244975984, 51.6078490746924], [-0.94299552290573, 51.60794563997599], [-0.943040847342192, 51.60798381288104], [-0.943186973159248, 51.608158666884215], [-0.943285889122319, 51.60825217104693], [-0.943509689787491, 51.60844031193307], [-0.94379690141149, 51.609007570967925], [-0.943824004868445, 51.60908424372538], [-0.943831400135399, 51.609201201602104], [-0.943839541642426, 51.60922375393887], [-0.943852077204152, 51.6092436483043], [-0.943874740412961, 51.60926273459518], [-0.943900416430683, 51.60927645299323], [-0.944008015202393, 51.60930709311221], [-0.944074894993692, 51.60934995527111], [-0.944126815315737, 51.60941516198104], [-0.944143328071964, 51.60945037786937], [-0.944150844233183, 51.609499899486615], [-0.944148608042361, 51.60953404761941], [-0.944074023202655, 51.60969882315075], [-0.94403415265091, 51.60986121332522], [-0.944017357658548, 51.60996266784037], [-0.943992023164905, 51.61030771903426], [-0.943965568458423, 51.61051428886229], [-0.943938629028152, 51.61067949277199], [-0.943919488028492, 51.61075754789674], [-0.943885949921455, 51.61083367520212], [-0.943827406881077, 51.61092935920088], [-0.943739589608875, 51.61104186395993], [-0.943638735204063, 51.61115604969767], [-0.943533757272514, 51.611261206608894], [-0.942952360107171, 51.61179457356613], [-0.942768364001955, 51.61194397664764], [-0.942436714102017, 51.61217027698273], [-0.942010518369458, 51.61248743929258], [-0.941742162181165, 51.61266215641604], [-0.941369087685306, 51.61286829880399], [-0.941218061678922, 51.612965845186196], [-0.941055044244821, 51.613082165678385], [-0.940962318642569, 51.61315685920963], [-0.940802313735133, 51.613329853845215], [-0.940532273923746, 51.613638528438315], [-0.940201080800705, 51.61403027273604], [-0.940058816377521, 51.614185443187054], [-0.939985695447699, 51.614286388653916], [-0.939953592073967, 51.614362527773245], [-0.939906859457064, 51.614508669589505], [-0.939802341993177, 51.61490335803689], [-0.939554942446072, 51.615603370947234], [-0.939452722231603, 51.61596121406953], [-0.939421935085161, 51.61604275989804], [-0.939387192811998, 51.616108085051245], [-0.939207265482904, 51.61639149465681], [-0.939036585027605, 51.61671185322904], [-0.938852844916865, 51.61697274874371], [-0.938765881571911, 51.61710953487875], [-0.938636321443754, 51.617400592062225], [-0.93858227703968, 51.617550263869646], [-0.938563060896774, 51.61763101488344], [-0.938557821588965, 51.617793716095726], [-0.938568952285691, 51.6178738422429], [-0.938586194898738, 51.61793963701825], [-0.93864824402059, 51.61806608070808], [-0.938712639101221, 51.61815388154161], [-0.938801458484915, 51.61824729803767], [-0.938902019778203, 51.61833272809444], [-0.939001577491258, 51.61839926656718], [-0.939080060597956, 51.6184404379885], [-0.939144458958051, 51.618466196342986], [-0.93924483456823, 51.61849767462955], [-0.939389936057716, 51.61853135511866], [-0.939533886937889, 51.618552436752374], [-0.939605967169062, 51.618558482633226], [-0.939704125343146, 51.618561167280205], [-0.940011869234288, 51.61855765138392], [-0.940970156479417, 51.61846828865034], [-0.942814559287174, 51.61834913395653], [-0.9433943585448, 51.61832378069166], [-0.943791844341078, 51.61831207069643], [-0.944095316626396, 51.61830580819228], [-0.944345189840605, 51.61830625638639], [-0.944633949874169, 51.618311549349706], [-0.944866264500346, 51.618321729423634], [-0.945069571918896, 51.61833704343469], [-0.945259736594118, 51.618358533188456], [-0.945405071369022, 51.6183823175338], [-0.945538707551366, 51.61841229079249], [-0.945670733169093, 51.618449442740584], [-0.945789657802543, 51.61849097274293], [-0.945898390514756, 51.618536007789324], [-0.946002624502939, 51.61858819565799], [-0.946144975691139, 51.61867849034559], [-0.946290660655923, 51.61881197458077], [-0.946424293873759, 51.618966930407886], [-0.94648587943588, 51.619052004215185], [-0.946597289998464, 51.61923103785771], [-0.946748500992991, 51.619500344620654], [-0.946865282768134, 51.619759451627154], [-0.94692090631825, 51.619852564183816], [-0.946986743272162, 51.619941272483025], [-0.947121992710119, 51.62008904866086], [-0.947221067183078, 51.620177155655796], [-0.947357337089385, 51.62028088174252], [-0.947636341593443, 51.62045871900467], [-0.947732020809812, 51.62050633282523], [-0.947832261440868, 51.62054409665008], [-0.948024909405708, 51.6205835873772], [-0.948272727755043, 51.62061098363029], [-0.94903310890345, 51.62064836261257], [-0.949342820854191, 51.62068530212313], [-0.949548509996597, 51.62072310869445], [-0.949603327033706, 51.620726296510135], [-0.94966121922192, 51.62072141934501], [-0.949725095662238, 51.62070760405018], [-0.949813979767225, 51.620674230793945], [-0.949850856696741, 51.620766275113425], [-0.949938127431095, 51.62092800552347], [-0.95012170684362, 51.62142328688538], [-0.950137689181391, 51.621481875301626], [-0.950144591409982, 51.621558365780544], [-0.950143525838059, 51.62166715485939], [-0.950086848280287, 51.62218276713024], [-0.950081566444785, 51.62234906486587], [-0.950091380322934, 51.6227375905417], [-0.950012857804674, 51.623198158520914], [-0.949963053357781, 51.62366617649237], [-0.94993621019599, 51.62382778558582], [-0.949887611273865, 51.62405573809743], [-0.94981748429385, 51.62434014525264], [-0.949698012983878, 51.6246969431444], [-0.949601071539472, 51.62520410239216], [-0.949519655994856, 51.62547671925938], [-0.949509640700394, 51.62553507516918], [-0.949509569744091, 51.62560071332227], [-0.949517625184728, 51.6256898023632], [-0.949539397678852, 51.62581048474923], [-0.949602831958219, 51.626066413978656], [-0.949622600072634, 51.6262113557699], [-0.949625807500304, 51.62644786389373], [-0.949588359660548, 51.62688092470566], [-0.949587162842075, 51.62718303218221], [-0.949593421398238, 51.627287390862], [-0.949641886384285, 51.62762860642186], [-0.949677564559904, 51.627772791296934], [-0.949732061930258, 51.62791534613564], [-0.949847071945823, 51.62812767746571], [-0.95005020451512, 51.62890367131774], [-0.949860358893705, 51.62924185674224], [-0.949849459019953, 51.62927592739189], [-0.949848649628705, 51.62931098742953], [-0.949857806222275, 51.62935243070728], [-0.949882540677514, 51.62940750068883], [-0.949782851646605, 51.62940750843079], [-0.949684104107472, 51.6296170289926], [-0.949619670293909, 51.62984214210067], [-0.949589348281571, 51.62990391300069], [-0.949478823262764, 51.63006027755304], [-0.949419643728549, 51.63018293320961], [-0.949378577882241, 51.63033452402259], [-0.949364251310331, 51.63051692549393], [-0.949339228920643, 51.63059942443184], [-0.949248633732607, 51.63076855530058], [-0.949181283974238, 51.630869557872636], [-0.949044504574139, 51.63103647701982], [-0.948893935504611, 51.63136242402941], [-0.948761069414249, 51.631297394415576], [-0.948669492362367, 51.63125880992652], [-0.948537801268757, 51.63120547966423], [-0.948447461288637, 51.63117589768262], [-0.948353982967507, 51.63115707745748], [-0.948302104865814, 51.63115121794117], [-0.948079606840815, 51.63115102360314], [-0.947964190602531, 51.63114369566099], [-0.94782149485015, 51.63112892992514], [-0.947725107052886, 51.63111098229264], [-0.947684910040859, 51.63109983219839], [-0.947483021604023, 51.63102069524269], [-0.947447137482345, 51.63101048287877], [-0.947306094892948, 51.630986739722026], [-0.947000710620611, 51.63094713644845], [-0.946674033898238, 51.6308911565172], [-0.946364247153943, 51.63079216747898], [-0.946230490849763, 51.63076579091048], [-0.946172752135344, 51.63076347450912], [-0.94612066649297, 51.630766603772976], [-0.945914796224295, 51.63079712600587], [-0.94583241748209, 51.63079818492752], [-0.945382953779145, 51.63067905708907], [-0.945085984219956, 51.63058827220451], [-0.944883205963743, 51.630547786680644], [-0.944304065189339, 51.630538086402446], [-0.94394898927073, 51.630523204990325], [-0.943611477254356, 51.63049858971805], [-0.943603681926519, 51.6307098224617], [-0.943277115569317, 51.63102249010073], [-0.943359247728321, 51.63109426279834], [-0.942862682241593, 51.631385618132356], [-0.942777562378065, 51.63144239822567], [-0.942532313252267, 51.63161282917167], [-0.942337892928893, 51.63177202827151], [-0.94226606523137, 51.631816339444626], [-0.942197377359527, 51.63184988892168], [-0.942115813951467, 51.631877927416205], [-0.941937005967162, 51.631924871353945], [-0.941512981586086, 51.63201636159427], [-0.94144898217334, 51.6320346671529], [-0.94125937051438, 51.632111184999914], [-0.940790185204025, 51.6323425346351], [-0.940501042462563, 51.632535943664614], [-0.940243238615803, 51.63268647504363], [-0.940131608045529, 51.632764593869275], [-0.939328651391563, 51.63361514453957], [-0.939011405652477, 51.634145481445906], [-0.93882930544315, 51.63451878632893], [-0.93850479164515, 51.63486472819315], [-0.93841585373771, 51.63483694950617], [-0.938308667759282, 51.63503379600045], [-0.938237520065274, 51.63511048065125], [-0.938174497877949, 51.635148574806536], [-0.938097155068085, 51.63518114448376], [-0.938014243480848, 51.63520467214815], [-0.937885103100742, 51.635227781700706], [-0.937899482630853, 51.63529265131639], [-0.937852791962712, 51.635312010611116], [-0.937756752174709, 51.63534081433219], [-0.93768849662133, 51.635355482713884], [-0.937445207164159, 51.63537845841074], [-0.937282775985471, 51.6354039635962], [-0.936848828519967, 51.635485456519916], [-0.935951432459366, 51.63561220386278], [-0.935719677036262, 51.635636179646525], [-0.935420148631615, 51.63565414571281], [-0.935249454884316, 51.63560044703531], [-0.935077590540852, 51.635535048401415], [-0.934717727795324, 51.63535285185533], [-0.934413155884105, 51.635216113905294], [-0.934240481559584, 51.635123731852076], [-0.934130824273522, 51.63505529964683], [-0.934018404467151, 51.63498144729724], [-0.93379675026591, 51.63482118293064], [-0.933679892303923, 51.6347517857655], [-0.933595523374065, 51.63471415412531], [-0.933350473747258, 51.63462740768713], [-0.933261876876166, 51.63458524160035], [-0.933052343088727, 51.63446285066096], [-0.932887751506176, 51.63439571653097], [-0.932638117941304, 51.63431971687678], [-0.932307197466639, 51.63419801967628], [-0.931343887912331, 51.63380981222079], [-0.931071830619705, 51.63376597498289], [-0.930956833347264, 51.63374065092008], [-0.930823331188951, 51.63370346918478], [-0.930701576222194, 51.633658301797674], [-0.930601553796263, 51.63361063468632], [-0.930506119022842, 51.63355221932683], [-0.930386739592999, 51.633467510133144], [-0.930286034494439, 51.633387466714524], [-0.930225334024314, 51.63332666999925], [-0.930188937852857, 51.633276884582266], [-0.930114567680391, 51.63312155131756], [-0.92999324620862, 51.63293521875163], [-0.929900400330813, 51.63282827174111], [-0.929602366751531, 51.6325378240622], [-0.929499431873266, 51.632429885607195], [-0.929341000864788, 51.63222433167361], [-0.929059923028374, 51.631889079042224], [-0.928963213558906, 51.63176231446386], [-0.928896162303318, 51.6316645934755], [-0.928844852932023, 51.631573310156845], [-0.928688841592085, 51.63126527289447], [-0.928672375509884, 51.6312282570475], [-0.928615004479859, 51.631026321392014], [-0.928599834825331, 51.63099561149414], [-0.928552267379979, 51.63092953870757], [-0.928477466267079, 51.630854225808044], [-0.928389580173335, 51.630782390113474], [-0.928294323595921, 51.6307167812279], [-0.928190294396403, 51.63065558801307], [-0.928078937075949, 51.630598823630024], [-0.927494137115659, 51.630339021667446], [-0.927177150281751, 51.63017967221046], [-0.927053070740772, 51.63011110151437], [-0.926922044883713, 51.63003077810591], [-0.926774152423019, 51.6299305188448], [-0.926569924361936, 51.62976860145066], [-0.926465515994788, 51.62966244509719], [-0.926222881099496, 51.62935271335746], [-0.925807083215573, 51.62885077488713], [-0.925685153671251, 51.62869140695483], [-0.925627779063265, 51.628612654944924], [-0.925107975398826, 51.62780494620014], [-0.925039238852947, 51.627717997425265], [-0.924853081975605, 51.627525670804864], [-0.924566287633664, 51.62725149768458], [-0.924018135317732, 51.62666651663998], [-0.9236755124427, 51.62631000590676], [-0.923506463123086, 51.62618886774415], [-0.92325024557972, 51.62602736696645], [-0.923179326155173, 51.62597186775246], [-0.923151247824846, 51.62593744208942], [-0.923025917353845, 51.62573937605691], [-0.922746731858051, 51.625388839233764], [-0.922647729925315, 51.625421200084226], [-0.922438316532782, 51.62517470633975], [-0.922266691774008, 51.62491866820555], [-0.922176577184834, 51.624819832363215], [-0.921722712186069, 51.62440384906751], [-0.921324388846087, 51.624082786314446], [-0.921078577970903, 51.623909687134365], [-0.920860652296657, 51.62377910436709], [-0.920574889783577, 51.623646099345635], [-0.920239048968319, 51.623492851580735], [-0.920014292502202, 51.62371107994427], [-0.919774493442185, 51.623954346092496], [-0.9196346398006, 51.62406455586703], [-0.919395541436808, 51.62427815528515], [-0.919291601043514, 51.624396787581134], [-0.919216417933559, 51.6245210794288], [-0.919153464283899, 51.62467785367513], [-0.919134125069682, 51.624762197061855], [-0.919115026043568, 51.62495803894169], [-0.919049238753011, 51.62517323267518], [-0.919009465019033, 51.625266379578875], [-0.918926652164549, 51.625407685106715], [-0.91889138185638, 51.62549368011671], [-0.918887531877765, 51.62553410703284], [-0.918896749679156, 51.62569334383204], [-0.918892707420934, 51.62574186144837], [-0.918872585162246, 51.62579832350382], [-0.918836276012485, 51.62586722482348], [-0.918763089019947, 51.62596815648993], [-0.918486277330256, 51.626309088016214], [-0.918317614737411, 51.62653682130949], [-0.917905561785174, 51.626975413689514], [-0.917718470441796, 51.62724883363936], [-0.917588198962995, 51.627380709193844], [-0.917518986462533, 51.627435819379606], [-0.917391270738013, 51.627520961779815], [-0.916852199941663, 51.62783249660931], [-0.916708494011591, 51.62822500463541], [-0.916564194300437, 51.62882431452802], [-0.91642514281193, 51.62950639562586], [-0.916399138398425, 51.62974892972319], [-0.916394191477189, 51.62995659074321], [-0.917260413231125, 51.62992321851857], [-0.917422640699178, 51.63166639247214], [-0.91745600722272, 51.63232848375385], [-0.917204699151121, 51.632324368705305], [-0.916787813832452, 51.632356490901394], [-0.916473041038736, 51.63240843616508], [-0.91615824611563, 51.63246127954521], [-0.916096846672852, 51.632491284427324], [-0.916000979824314, 51.632573122584574], [-0.916035541448316, 51.63300234215989], [-0.916058746179642, 51.633180590521675], [-0.916070697537387, 51.63322475979131], [-0.916098260729099, 51.63328076225654], [-0.916287121367376, 51.6334803208717], [-0.916556537933578, 51.63369500893812], [-0.916833436931067, 51.63389897542989], [-0.916980624704717, 51.63396776999687], [-0.917236275570907, 51.634093312450645], [-0.91746761535009, 51.63414759643489], [-0.917599467742121, 51.63382870989293], [-0.917652284973834, 51.63367364156546], [-0.917677934007693, 51.63362802065708], [-0.917745133700401, 51.63359716923921], [-0.917749446066394, 51.633598108140106], [-0.917778102484095, 51.633608262991594], [-0.918084580428658, 51.633662338963], [-0.918258883815884, 51.633684625273325], [-0.918506861448772, 51.63370758977881], [-0.918953829589691, 51.63374767133924], [-0.919245145699076, 51.633771033193085], [-0.919300707852053, 51.63386505735126], [-0.919518444759651, 51.63449197843591], [-0.919277685382965, 51.63446908250848], [-0.919031520477806, 51.63467362436313], [-0.918786199566619, 51.63490335001199], [-0.918632752044247, 51.63503681158531], [-0.918623327237537, 51.63512933850577], [-0.918590569006466, 51.635413172104], [-0.918679820058316, 51.63554886817429], [-0.918329488250497, 51.63557621368664], [-0.918276435808259, 51.635741170885815], [-0.918247752304029, 51.6360358318421], [-0.918226764712395, 51.6364321689642], [-0.918316733144818, 51.63702374696847], [-0.918287332378286, 51.63783452012518], [-0.918306713699577, 51.63835621240955], [-0.918316674296085, 51.639213205140855], [-0.918347519668651, 51.639799742499974], [-0.918322169732004, 51.63995416480466], [-0.918318885834364, 51.64003146244247], [-0.91832686087795, 51.64012145202931], [-0.91837911416845, 51.640354816042915], [-0.918418495846573, 51.64070405330022], [-0.918530296534871, 51.64128953760163], [-0.918512952473936, 51.64147190762244], [-0.918367217757134, 51.64200916315153], [-0.917905817511154, 51.6420255938785], [-0.917874522823857, 51.64200462484983], [-0.9178264462409, 51.64196012300076], [-0.917792775459127, 51.641917552189355], [-0.917773553228143, 51.64187511449974], [-0.917765526057023, 51.64184806570082], [-0.917757894232724, 51.6417436926823], [-0.917749532884981, 51.64142711089125], [-0.917739557627689, 51.64136048104305], [-0.917720785029217, 51.641299165096676], [-0.917688816437575, 51.64124581999865], [-0.917649452591449, 51.641199600032465], [-0.917568381483579, 51.64114490323613], [-0.917433423830488, 51.64098630616572], [-0.917315173490429, 51.64079369481265], [-0.916601390868836, 51.640243120219885], [-0.916329281834837, 51.640018517003504], [-0.916001068304932, 51.63966211774633], [-0.915790319174844, 51.63947044935813], [-0.915502073944432, 51.63913509831614], [-0.915393357554307, 51.63902799332443], [-0.915169439572157, 51.63884339546647], [-0.914312592230519, 51.638234837864296], [-0.913969150495335, 51.63797270396478], [-0.913808719070197, 51.63773204326735], [-0.913709021859032, 51.63761063348384], [-0.913238840648949, 51.637814889395024], [-0.912211197236081, 51.63818662075986], [-0.912057780107923, 51.6382571327065], [-0.911911629192503, 51.63832591344631], [-0.911683066608314, 51.6384568717294], [-0.911571655864317, 51.638583520328496], [-0.910821072629623, 51.63897039510019], [-0.910799442348496, 51.63890815232427], [-0.910457034748542, 51.63884473254883], [-0.90959863753988, 51.63872527019996], [-0.909397970101408, 51.639078576087414], [-0.909048252097236, 51.63925965643008], [-0.909362542404515, 51.63959166868019], [-0.90780907162756, 51.64013291512084], [-0.906217399025103, 51.640939038154336], [-0.905898125060113, 51.64111499768922], [-0.905490384709512, 51.641363863281036], [-0.905329841704473, 51.64154939281248], [-0.905189541321435, 51.641794455508446], [-0.90489098319803, 51.64194992468491], [-0.904781623731163, 51.641990266433346], [-0.904676706895303, 51.64202615370086], [-0.904609919053975, 51.64203901826923], [-0.904237228330216, 51.64209218907456], [-0.90337364044862, 51.64224597828853], [-0.902975191138407, 51.642348358507896], [-0.90292303291413, 51.6422939216028], [-0.902563354675933, 51.64240655335107], [-0.902346768622897, 51.642458479170756], [-0.900824166346957, 51.64291090498388], [-0.900831401206159, 51.64297031739377], [-0.900456613238591, 51.64299018760407], [-0.900019098619797, 51.64297440185565], [-0.899740380937974, 51.64290615240652], [-0.899740489711103, 51.64290165761423], [-0.899316872364163, 51.642849133775655], [-0.899203336991784, 51.642822893203494], [-0.898949902655656, 51.64272520647125], [-0.898783095909619, 51.642631028913314], [-0.898613530793898, 51.64253143027416], [-0.898274969154989, 51.64230885935864], [-0.898003026265053, 51.642080618381755], [-0.897815191816853, 51.641840577798526], [-0.897681652652772, 51.6416262230417], [-0.897327401428262, 51.64091885338664], [-0.896908641882592, 51.6401308512027], [-0.896689777704333, 51.63985994571793], [-0.896199107519928, 51.639356299928586], [-0.896147069948886, 51.63929736526477], [-0.896071667668875, 51.63912941223961], [-0.896034388155249, 51.63881974973283], [-0.89604243255033, 51.63866696761571], [-0.896079873457203, 51.63849378104931], [-0.896158355572289, 51.63829670279626], [-0.896345617779906, 51.63796397393339], [-0.896436991088377, 51.637771512438086], [-0.896627579786388, 51.63748017587825], [-0.896853716275347, 51.63721255114492], [-0.896930541034958, 51.63714313797598], [-0.897052325259386, 51.63706695367484], [-0.897622203318074, 51.636806151704704], [-0.897875248140837, 51.636679946210485], [-0.898045509693898, 51.63657094674504], [-0.898161794997489, 51.63648302058021], [-0.898300490282884, 51.636364732965696], [-0.898761753797595, 51.63587451909389], [-0.898944791614438, 51.635595696246455], [-0.899167964890093, 51.63497197055003], [-0.899296205851425, 51.63450920414348], [-0.899574174378538, 51.633591065468096], [-0.89965934952667, 51.63323579470252], [-0.899745200652967, 51.632733067337156], [-0.89977291429982, 51.632065248259224], [-0.899749317297925, 51.63190587518938], [-0.899730833669311, 51.631833768913715], [-0.899698165870897, 51.631750739777836], [-0.89965967663145, 51.63166945441679], [-0.899415121605884, 51.63126703489972], [-0.899342021743563, 51.6311233827535], [-0.899274678557411, 51.630980683675816], [-0.899221406706553, 51.63067446858268], [-0.899099405183406, 51.63046202142283], [-0.899036514315775, 51.63037421293725], [-0.898969246754073, 51.63028816171176], [-0.898790586842518, 51.63008867047265], [-0.898592010806669, 51.62987640386868], [-0.898497321924236, 51.62978919602221], [-0.898330098469121, 51.62965455114822], [-0.898092642525963, 51.62949676796704], [-0.897090362270362, 51.62894426419184], [-0.896737033461809, 51.62879887742956], [-0.896347312922056, 51.6286648367393], [-0.895633444660858, 51.62837398981453], [-0.895432402381131, 51.628264199314984], [-0.895328663542796, 51.62819308870188], [-0.895257753282041, 51.62813847178444], [-0.895144755729953, 51.62803220648194], [-0.894948239644532, 51.627795675481295], [-0.894944118635818, 51.62766795529761], [-0.894659948504904, 51.62723368184], [-0.894597856997988, 51.62711350846984], [-0.894557343909314, 51.62699713484451], [-0.894469809950127, 51.62655661915932], [-0.894297931114171, 51.625960652861906], [-0.894027819576293, 51.62530531541029], [-0.893931965007508, 51.62514795788166], [-0.893770350871199, 51.62496210671055], [-0.893637995566781, 51.62476124514902], [-0.893507481839104, 51.62466290563429], [-0.892108104715385, 51.62369479825078], [-0.891788795844237, 51.623459800649094], [-0.891922368328922, 51.62337294285213], [-0.891402229815371, 51.62296161084893], [-0.891224922435199, 51.622768414566416], [-0.890089770742591, 51.621276764770215], [-0.890188416566163, 51.62120036880181], [-0.889947380146256, 51.62101466068101], [-0.889727152716072, 51.62086421627997], [-0.889328903798693, 51.62066892786315], [-0.889153387824523, 51.620758083474584], [-0.888409981594066, 51.6201459098237], [-0.888016456293258, 51.619876030785385], [-0.887588982852847, 51.619754191291285], [-0.887143566599165, 51.61965735685454], [-0.88701981132148, 51.61963820065132], [-0.886790744842007, 51.619613550199404], [-0.886603228328527, 51.619602780759124], [-0.886388075513318, 51.619599841439666], [-0.886090409498186, 51.61960421155123], [-0.8851368584814, 51.61967159165818], [-0.883828125903616, 51.61979133688442], [-0.883515973065361, 51.619797361107345], [-0.883424375160774, 51.6198216668555], [-0.883259776293847, 51.619877648328995], [-0.883163867754863, 51.61990101371408], [-0.883044634749604, 51.619815357981636], [-0.881854770311083, 51.61956485587701], [-0.881704286246311, 51.61951666620604], [-0.881635675440863, 51.619487239450166], [-0.881560131370525, 51.619446057447796], [-0.881477720403852, 51.619390423316226], [-0.881374708667671, 51.619291432867335], [-0.880834298239682, 51.61853547912722], [-0.880617549323506, 51.618127888748454], [-0.880388345702594, 51.61816796449318], [-0.879226788544387, 51.6185884841998], [-0.878534686661489, 51.61883184500677], [-0.878385021629543, 51.61898507235025], [-0.878148819949825, 51.61913297697072], [-0.878102165244257, 51.61915051459153], [-0.87804120240859, 51.61916252048532], [-0.877967464227806, 51.619165412606506], [-0.877896924603018, 51.61915574690363], [-0.877839648002824, 51.61913541789456], [-0.877812586845032, 51.61911987344738], [-0.877382402665225, 51.61869944717381], [-0.877261875140598, 51.61866682400238], [-0.877087293116294, 51.618600414623565], [-0.876592344555959, 51.61846350297477], [-0.876408990128558, 51.61845995037962], [-0.876374465270622, 51.61845422502283], [-0.876347205240439, 51.61844677083749], [-0.87630299358364, 51.61842386858449], [-0.876241963569583, 51.618380124514495], [-0.876216636094276, 51.618352907107045], [-0.876152781748704, 51.618131100785114], [-0.876106882196741, 51.61811807314475], [-0.876305643178539, 51.617614643124426], [-0.875030363348109, 51.6174927341714], [-0.874705473526163, 51.61748872204597], [-0.874564111923802, 51.6174810731233], [-0.874279482039409, 51.61730930128958], [-0.874259717266618, 51.61699889890464], [-0.874416434195306, 51.61673604585861], [-0.874423036602998, 51.61652750219062], [-0.870144618410033, 51.61769939147719], [-0.870074692270606, 51.617607003497994], [-0.869665459226217, 51.61768399010514], [-0.869137937974611, 51.617812887107476], [-0.868711126950696, 51.61789959196275], [-0.868460959800069, 51.617969115035805], [-0.866874516019656, 51.61827841686334], [-0.866642434191741, 51.6183175388698], [-0.866517885416195, 51.61833072340073], [-0.866392071649004, 51.61833670224208], [-0.865776872894858, 51.61833166083683], [-0.865633662902087, 51.618340168339564], [-0.865493072065054, 51.618359490991885], [-0.864874419821269, 51.618492883413026], [-0.864829070270363, 51.61851582340227], [-0.8648101986804, 51.61846169086974], [-0.864778464993556, 51.618402038980314], [-0.864733824417545, 51.61833866562683], [-0.864681918741689, 51.61827702035103], [-0.864649512487616, 51.61824433697217], [-0.864492159027339, 51.61812502442397], [-0.864510219622979, 51.618037979732996], [-0.864490008258273, 51.61792179156664], [-0.863791866117017, 51.616668790850674], [-0.863578496430752, 51.61619016667409], [-0.863939572338851, 51.6160749702936], [-0.864141702322916, 51.61602027805823], [-0.864343742093738, 51.615969181278444], [-0.864684853799959, 51.61590144547291], [-0.864287415633653, 51.61573755014447], [-0.864114344880943, 51.615611790807684], [-0.86394143216696, 51.615479738556914], [-0.863424226660599, 51.6150224515856], [-0.863108525016747, 51.61470918210108], [-0.862999136822108, 51.61463618943345], [-0.862947760773663, 51.614611414387845], [-0.862827479233939, 51.614569786988696], [-0.862764327092327, 51.6145538895073], [-0.862690954996651, 51.614542388851355], [-0.862422671693898, 51.614528100870835], [-0.862278208948609, 51.61452939875511], [-0.862025067586916, 51.614544929155834], [-0.861633333855888, 51.61461576315295], [-0.861195617216796, 51.61467715820802], [-0.860991546767721, 51.61469406144679], [-0.860819513274215, 51.61470048511226], [-0.860591345418716, 51.61469917048917], [-0.860366335624517, 51.61468709604235], [-0.860199196800327, 51.61467108707321], [-0.860140174693704, 51.6146633207896], [-0.859842784619867, 51.61460018922178], [-0.85969929013584, 51.61456282905675], [-0.859501466379857, 51.61450336097874], [-0.859306643699259, 51.614439425872085], [-0.859175017225196, 51.614389591981386], [-0.858977780895874, 51.61430675031806], [-0.858172868778381, 51.61392127488393], [-0.856305510909038, 51.61299763777437], [-0.855879431428414, 51.61282624136621], [-0.855413827571698, 51.612676038205095], [-0.855073660630441, 51.61259179657028], [-0.854915624510577, 51.612558784566126], [-0.854688372582268, 51.61252150056368], [-0.854459541396129, 51.6124895957323], [-0.854208848612115, 51.61246556965946], [-0.853413812340721, 51.612436228916096], [-0.851724243907319, 51.61242871018406], [-0.851450292115, 51.612410744947404], [-0.850998615679464, 51.61233888823236], [-0.850653274334699, 51.61223120468302], [-0.850372939737194, 51.61235164666859], [-0.850315593337778, 51.61233490012849], [-0.850193999216673, 51.612288751000705], [-0.850146601119627, 51.612278395984944], [-0.849926028861458, 51.61226274823948], [-0.849854084982468, 51.61225215268858], [-0.849714847013531, 51.612218418620564], [-0.849473435162227, 51.61217019573735], [-0.849372523204365, 51.61216291272777], [-0.849235958321253, 51.61219484371945], [-0.849170915863905, 51.6121969037703], [-0.849112126238191, 51.61218014249445], [-0.8487984760956, 51.61201881385575], [-0.848813983178796, 51.61186251023449], [-0.848805967905994, 51.611779707971536], [-0.848777693193183, 51.61169850541887], [-0.848751669639592, 51.61164250170296], [-0.848740414389996, 51.61163070213332], [-0.848685616135578, 51.61162746733029], [-0.848598109857592, 51.61148993537107], [-0.848561752293423, 51.61144282198033], [-0.848420551583887, 51.61131555337684], [-0.848346143135118, 51.61123120073643], [-0.848017978126262, 51.61073074025961], [-0.84803240586268, 51.61067423405594], [-0.848009203184881, 51.61062095534751], [-0.848010806265629, 51.61061467688053], [-0.848360723390725, 51.61054078070849], [-0.848731046077576, 51.61040234328455], [-0.848814480324059, 51.61035820278237], [-0.848820437461021, 51.610351067821576], [-0.848690278305866, 51.610072847084595], [-0.847947554822518, 51.60900543974003], [-0.847435103308081, 51.6083125448088], [-0.847167998407497, 51.60796823756615], [-0.846186886755928, 51.60662333116728], [-0.845549998419521, 51.605828497430636], [-0.845383680959569, 51.60566770865375], [-0.844840468159951, 51.60522267062485], [-0.84443530295085, 51.60497141150611], [-0.844232696249957, 51.60481835643492], [-0.843486943931864, 51.60416181103064], [-0.84332558359401, 51.60420428093958], [-0.842908147301968, 51.603868373383044], [-0.842663709069561, 51.603714004109015], [-0.842310199280505, 51.603533382087996], [-0.841471682375652, 51.60311958453644], [-0.841215384127901, 51.602977683579475], [-0.840873068217364, 51.60281155440105], [-0.840467421086961, 51.602637605395635], [-0.840268344470896, 51.602516948405764], [-0.840203154295604, 51.60246864832527], [-0.838474883614574, 51.601841924417336], [-0.838334815858368, 51.60178568911777], [-0.838125139250388, 51.60168470536249], [-0.837520083534699, 51.60134782062488], [-0.837365310402971, 51.60124558073874], [-0.837143016970701, 51.6010734356079], [-0.83702163004049, 51.600964332538595], [-0.836879440722268, 51.60082175386177], [-0.836733036616179, 51.60067463738169], [-0.836105420124444, 51.59992210370809], [-0.836001567218505, 51.59980508080317], [-0.835894758960057, 51.59969072601903], [-0.835646409012494, 51.5994652683849], [-0.835572705263831, 51.59941148620318], [-0.835355212679077, 51.599278049641256], [-0.835001490423373, 51.59910819321327], [-0.834666328550124, 51.59894661249016], [-0.834023851532118, 51.59860753956394], [-0.833813699592692, 51.59846967713012], [-0.832219972267628, 51.59727861587006], [-0.831975375091702, 51.59713321406168], [-0.83180286996819, 51.597047874561696], [-0.83156138306724, 51.59695015903964], [-0.831279067386554, 51.596868221715724], [-0.831119729288761, 51.59683246683902], [-0.830996129682144, 51.596810555210986], [-0.830798964246538, 51.59678611250204], [-0.829935838169309, 51.596720865686486], [-0.82967342169104, 51.596707460026586], [-0.829378950815281, 51.59670542343618], [-0.828672101908656, 51.596738836236966], [-0.828529092462618, 51.59674190522934], [-0.828241907711544, 51.596737240965595], [-0.828066024571149, 51.59672739285258], [-0.827854311754233, 51.596707295846045], [-0.827399248313258, 51.59666228882735], [-0.827164974703315, 51.59662128423301], [-0.827063074447412, 51.59659778687348], [-0.826830893268571, 51.59653162563389], [-0.826403126611598, 51.596379885757386], [-0.826320361645679, 51.596342192238744], [-0.826196596762853, 51.596270819297594], [-0.825930135887572, 51.596078429107884], [-0.825702044863314, 51.59590980062742], [-0.825239717878873, 51.595531118786504], [-0.824901250965003, 51.59522021379687], [-0.824412039116432, 51.59470908081712], [-0.8242790371805, 51.59460434384618], [-0.824162427084317, 51.59453573788591], [-0.823734544991122, 51.59433363318264], [-0.822923577534385, 51.59387232098135], [-0.82274220720895, 51.593740122024236], [-0.822758790294358, 51.59343366962803], [-0.822450529949737, 51.592123177421634], [-0.822408018987733, 51.591980681321466], [-0.82236394886053, 51.59184266543808], [-0.822242174035691, 51.59158338051977], [-0.821801765862476, 51.5908065697487], [-0.821372709449585, 51.59009371260957], [-0.821171850754746, 51.58982284235581], [-0.820679968304875, 51.58936291919855], [-0.820417155492676, 51.58914357740762], [-0.82015811620844, 51.5888901042506], [-0.820045903377484, 51.58876399099103], [-0.81975498206002, 51.5884040936899], [-0.819793038416411, 51.58838379523831], [-0.819648800144719, 51.588268149727725], [-0.819147039514258, 51.58763368041164], [-0.818936357700162, 51.58740856531028], [-0.818746726401906, 51.58698404449756], [-0.818744261992127, 51.58691208559554], [-0.818786542624285, 51.586561832259704], [-0.818798419467402, 51.58638211648965], [-0.818772601288344, 51.58593047014409], [-0.818622316220491, 51.585380460186784], [-0.818493730937228, 51.58471737211902], [-0.818460174123387, 51.58461992329734], [-0.818316632401033, 51.58436670899539], [-0.818092592164715, 51.58404524580265], [-0.817774082795079, 51.58341531231479], [-0.817553796530972, 51.58311636524129], [-0.817445537064436, 51.58300557512581], [-0.81689125274485, 51.582562990062094], [-0.816348587477007, 51.58217357091916], [-0.816214612729635, 51.58210837837547], [-0.816144330954904, 51.58209148442308], [-0.816059129697027, 51.58209332267878], [-0.815742672724781, 51.5820523651453], [-0.815217212787465, 51.58194545592985], [-0.815002344756643, 51.58188304223224], [-0.814826435408141, 51.5818210214772], [-0.814485295861823, 51.581730356582035], [-0.81444044205173, 51.581790148477246], [-0.813566956536122, 51.581635656767844], [-0.813282023122958, 51.58154825394594], [-0.813052037332166, 51.581456910143594], [-0.812870182657061, 51.581346270732034], [-0.812790810356639, 51.58129061819263], [-0.812604263086127, 51.581138568732094], [-0.812386509085548, 51.58085492331321], [-0.812249092317067, 51.58070067277682], [-0.812167619564544, 51.58055957666617], [-0.812051961231651, 51.58029045130041], [-0.812042798783181, 51.580254391465495], [-0.812034433182585, 51.580187767648724], [-0.812033188044369, 51.58012481260171], [-0.812058064730261, 51.580000977815104], [-0.81229781440549, 51.579440518478464], [-0.812247901650195, 51.57941753400863], [-0.812446355706805, 51.57916777205078], [-0.81277233113049, 51.578787120404634], [-0.813191367818544, 51.57821318632392], [-0.813476583358647, 51.57767926033569], [-0.81372993476285, 51.57714950751218], [-0.813894821439398, 51.57669169369027], [-0.813998634879093, 51.57614064720803], [-0.814138744624452, 51.57508193151095], [-0.814120940539715, 51.57493428638376], [-0.81419874804071, 51.57321943977239], [-0.814492542549023, 51.572575897898666], [-0.814547744449169, 51.57211787423915], [-0.814549364628156, 51.57200009817749], [-0.81449843948966, 51.57157247390041], [-0.81447275908744, 51.57022974030085], [-0.814470739157426, 51.56964165674743], [-0.814429823166273, 51.56938407823071], [-0.814416473674158, 51.5693425811485], [-0.814362577800679, 51.569251219648685], [-0.81406844007837, 51.5689659058573], [-0.813908308238922, 51.56874308971205], [-0.813853532979604, 51.56863013877188], [-0.81375715260415, 51.56839717647337], [-0.81371284208748, 51.56815934527622], [-0.813667666933597, 51.567788426746645], [-0.813915408556528, 51.567527470860746], [-0.814280993234198, 51.56684059466537], [-0.814704823511867, 51.56613272518902], [-0.814994772052415, 51.56569055892733], [-0.815202529336662, 51.56519091397622], [-0.815219131565213, 51.56505170869626], [-0.815351636137841, 51.564671793906264], [-0.815511116853932, 51.56436408558186], [-0.815565592175225, 51.5642108755608], [-0.815662011458114, 51.564053592855515], [-0.815731002538058, 51.56389693250399], [-0.815762954470268, 51.56377766396064], [-0.815882314039101, 51.56307031436626], [-0.815899206541573, 51.563030920866616], [-0.815918960262566, 51.5629924554096], [-0.816100387305838, 51.56272812828101], [-0.816239061970809, 51.562387838558415], [-0.816351227865814, 51.56217946080997], [-0.816402225233145, 51.562104443964415], [-0.816445731089239, 51.56204014171416], [-0.816755073070336, 51.56173843863565], [-0.81682883069147, 51.5615089920632], [-0.81709149295673, 51.56100450196165], [-0.817126546068515, 51.5610435199925], [-0.817036868291134, 51.56144185218239], [-0.817602599672938, 51.56148891511105], [-0.817650902097453, 51.56129517879352], [-0.81772376875861, 51.56109989153342], [-0.818544773098936, 51.56114952106405], [-0.818940645385275, 51.56112652991029], [-0.819286252234888, 51.56087194248433], [-0.820505192935939, 51.560762809232635], [-0.821152924392013, 51.56109751750433], [-0.821401734784996, 51.56112699167495], [-0.821468077854438, 51.561127657861135], [-0.821837057068471, 51.56108460493917], [-0.822551882107614, 51.56083281445182], [-0.822991148836609, 51.56069335159132], [-0.823298868990794, 51.56056425765945], [-0.823427756279142, 51.560489119484224], [-0.823816316952276, 51.56018999039105], [-0.823841530161624, 51.56016326766115], [-0.823879440321637, 51.5600917131651], [-0.823939663402364, 51.55926686943448], [-0.824000930577316, 51.55924050793579], [-0.823876052668265, 51.55798579953388], [-0.823797968341331, 51.557154174451156], [-0.823813910366727, 51.55698348995032], [-0.824268965579194, 51.556733581409404], [-0.824612742777356, 51.55649154853787], [-0.826344281900068, 51.55484359477631], [-0.826657025878971, 51.55457337099326], [-0.827233265990788, 51.554040521447654], [-0.827929376968602, 51.55344502444081], [-0.828029419518581, 51.553368693973354], [-0.828246668974642, 51.55322159923911], [-0.828485269800709, 51.5530855074047], [-0.828605105979095, 51.55302466009866], [-0.829372820563392, 51.55267264797847], [-0.830416538296143, 51.552300003050114], [-0.830341853307235, 51.55217517181714], [-0.830015969895102, 51.55217192349864], [-0.82991663595149, 51.55216463892005], [-0.829524156953837, 51.55211486704629], [-0.829282415323888, 51.552092673855796], [-0.828838545910614, 51.55207835426137], [-0.828599504055965, 51.55206338004898], [-0.828680519991051, 51.55199764928292], [-0.828534433277995, 51.55195752639793], [-0.828384829125967, 51.55188589688778], [-0.827987906418731, 51.55167242458396], [-0.827957477145366, 51.551621766572], [-0.827834232346298, 51.55159086272802], [-0.827633977763617, 51.551525919798664], [-0.827259642164726, 51.55144395104261], [-0.826879262755715, 51.5513727108443], [-0.826619197529414, 51.551334143723224], [-0.825020961294276, 51.55117248609027], [-0.825087548806697, 51.55099511486544], [-0.825080332863119, 51.55093929339289], [-0.825041927300218, 51.55086247849746], [-0.82502361605882, 51.55078946149474], [-0.825044884876699, 51.55069166368164], [-0.825058487270179, 51.550667521970404], [-0.82509857658956, 51.550622964257876], [-0.825145597538488, 51.55058926609727], [-0.825325151596322, 51.5505056412203], [-0.824909915146001, 51.550164291306395], [-0.82525013660448, 51.550002248032946], [-0.825332063085088, 51.549957209837], [-0.825638185418255, 51.54977504214384], [-0.82578350044032, 51.54967668704559], [-0.825923116734683, 51.54957557721289], [-0.826170603160388, 51.54937393870707], [-0.826371785812396, 51.54917813090106], [-0.826492161334072, 51.549039961540565], [-0.826611394860751, 51.548890091280356], [-0.82670116630089, 51.54876420424681], [-0.826782355507479, 51.54863553380353], [-0.826823019292071, 51.54856850170786], [-0.827062757600335, 51.548106920435835], [-0.827101368877001, 51.54800749719491], [-0.827194201898492, 51.54770629998806], [-0.827307057244965, 51.54741159704493], [-0.827582602426052, 51.54684696658141], [-0.827901482950928, 51.54639156924703], [-0.828226190833503, 51.54604592938406], [-0.828636291311094, 51.545744301711125], [-0.82879259021163, 51.54566673370386], [-0.828904643767125, 51.545627388779295], [-0.829074413403866, 51.54558682127211], [-0.829642313890905, 51.54554213206049], [-0.831137752395514, 51.5457125947128], [-0.831296230672639, 51.545718668970665], [-0.831381409559054, 51.545715021306385], [-0.831520416985355, 51.54569302674314], [-0.831658465956176, 51.54565213966273], [-0.832162223002951, 51.54540897973132], [-0.832259763552867, 51.545373083913695], [-0.832342495362879, 51.54535232675641], [-0.832449690786029, 51.545333611293344], [-0.832560958333776, 51.54532482723805], [-0.832748224427793, 51.54533298427906], [-0.833594396864807, 51.5455158387706], [-0.833803468208608, 51.5455736658201], [-0.834066591719905, 51.54566080332341], [-0.834319302360527, 51.54576042533909], [-0.834632701147966, 51.545911902800114], [-0.834743597643834, 51.54597414830218], [-0.834972095381443, 51.546118487532766], [-0.835101437527799, 51.546192605160904], [-0.835308853525451, 51.54642845092972], [-0.835597379030446, 51.546650714213946], [-0.835675530378703, 51.54669644865621], [-0.835765285050956, 51.54673960061442], [-0.835946924814448, 51.54679895002405], [-0.836738145066418, 51.54693268079673], [-0.837616543696299, 51.54698454508781], [-0.837668585980954, 51.546979665457], [-0.837867989708348, 51.546964555807335], [-0.83797367625272, 51.54694851789646], [-0.838105566972017, 51.54692284834119], [-0.838233315283634, 51.54688994418392], [-0.838329229403341, 51.54686122067977], [-0.838482151664417, 51.546802489195365], [-0.839036827411148, 51.54642762424692], [-0.83955396219585, 51.54605418383688], [-0.840116011657223, 51.54567219327131], [-0.840736658187885, 51.54525391246058], [-0.840941426195899, 51.54514083988849], [-0.841049279937165, 51.54509604683764], [-0.841194847094701, 51.5450426342828], [-0.841299520083949, 51.545009498946165], [-0.841898633062652, 51.544870644649805], [-0.842282244574123, 51.54481328536381], [-0.842762474116396, 51.54475597844143], [-0.843565178344648, 51.54477737891959], [-0.844086979548171, 51.54484366398717], [-0.845732620874625, 51.545006428046236], [-0.847066038668597, 51.54519847249473], [-0.847735465249349, 51.545415455459946], [-0.84773690700669, 51.54541546961599], [-0.848634731053663, 51.54572550693968], [-0.849946581441456, 51.54620234699594], [-0.850255922443757, 51.54628810259981], [-0.850450510421732, 51.5463493547082], [-0.850677807173489, 51.54642891042725], [-0.850994850981171, 51.546552505063595], [-0.852786328510159, 51.547342426670774], [-0.85300310746802, 51.547496506935786], [-0.853571212311598, 51.54778799706584], [-0.854020445083318, 51.54798930492918], [-0.854581807452525, 51.548205193183556], [-0.85478620907829, 51.54827822314386], [-0.854963577157503, 51.54833660211785], [-0.855161244465997, 51.54839068294659], [-0.855663052553423, 51.5485088736389], [-0.856166529832507, 51.54867563412252], [-0.856279761006, 51.54870371304979], [-0.856530960852844, 51.54875111981111], [-0.856804082121709, 51.54878705024175], [-0.857112033920981, 51.54881432744164], [-0.857381573472553, 51.548820548731904], [-0.857549123049589, 51.54881049056259], [-0.857844479857821, 51.548764809719025], [-0.858057604662229, 51.54872012637499], [-0.858337617310588, 51.54865361386837], [-0.858552497890933, 51.54859635820055], [-0.859049392399301, 51.548450127924276], [-0.859439117962245, 51.5483792842905], [-0.859697682244768, 51.54836291412634], [-0.859779823131423, 51.54836551056866], [-0.860170027263243, 51.548390881318824], [-0.860456238387038, 51.54842243448379], [-0.861009536104037, 51.548500639150554], [-0.861158816462501, 51.54852906321894], [-0.861352413335375, 51.54857320311727], [-0.861544411683264, 51.54862362144007], [-0.861731905414109, 51.5486811891874], [-0.862073439754406, 51.548807688741114], [-0.86254414698236, 51.54901726458452], [-0.86282747298222, 51.54916477803516], [-0.863015068128655, 51.549276295417606], [-0.863120154717426, 51.549342054318615], [-0.863285809311142, 51.54946594721784], [-0.863418211576468, 51.54959311456195], [-0.863530092020445, 51.54973357070672], [-0.863653360363745, 51.549937978681236], [-0.863733641061499, 51.550131180181424], [-0.863790336700716, 51.5503448343906], [-0.863824973966162, 51.550691353426465], [-0.863841717303786, 51.55100353042492], [-0.863889686614544, 51.55116225019172], [-0.863971345177536, 51.55135816235228], [-0.864192531443895, 51.5518009005184], [-0.864636908176204, 51.552606367995786], [-0.864885616784935, 51.55304487507487], [-0.864984710926909, 51.55317801261536], [-0.865042267578469, 51.5532415116859], [-0.86524661818949, 51.553434113390985], [-0.866448255146234, 51.55464702695421], [-0.866553639357719, 51.55475954277147], [-0.86713929523259, 51.555454866418074], [-0.86728119491555, 51.55560729781788], [-0.867357192432134, 51.55568356216347], [-0.867846797612144, 51.55612348793147], [-0.867948777192819, 51.5561991033314], [-0.868039688780355, 51.55625572917072], [-0.868162193200772, 51.55631805467487], [-0.868334859667638, 51.55639345221028], [-0.868507816648064, 51.556457162985154], [-0.868686743286876, 51.556512838449954], [-0.868885971532242, 51.55656421341042], [-0.869870431325262, 51.55700170522159], [-0.870538382015661, 51.557289577406756], [-0.87065953954758, 51.55734829060127], [-0.870968323528286, 51.55751940747054], [-0.871084688448939, 51.55759695683154], [-0.871173919806704, 51.55766345498963], [-0.871421843971099, 51.55790412108149], [-0.871517352960249, 51.558008444760674], [-0.871560414081151, 51.55807539786269], [-0.871689483441928, 51.558339198343305], [-0.871715457861831, 51.558455441841], [-0.871819115572425, 51.558871857901316], [-0.872116688986198, 51.559438501590606], [-0.87224925001588, 51.559678057158926], [-0.872395481580982, 51.5598898694294], [-0.872503199025109, 51.56002578071336], [-0.872616797176149, 51.56015725249727], [-0.872767427555836, 51.560307962534345], [-0.873712440787397, 51.560887112412736], [-0.874019840047307, 51.56105730856152], [-0.874413245272104, 51.56124990894107], [-0.875159636577155, 51.56157807024888], [-0.875469862748955, 51.561692540724444], [-0.875618818634067, 51.561736229028845], [-0.87605776549836, 51.56183754414599], [-0.876366373823489, 51.56190074371407], [-0.87668521195865, 51.561958645316366], [-0.876968369886447, 51.56200091867397], [-0.877197163756339, 51.56202468778881], [-0.877516822654725, 51.5620493254706], [-0.878098847659676, 51.56208186543848], [-0.879220205739232, 51.56212315048378], [-0.879742407250114, 51.562124539056946], [-0.8803196812009, 51.56211566057546], [-0.88047709073344, 51.562109069498774], [-0.880781923890852, 51.5620912956137], [-0.881058065229737, 51.56206695318683], [-0.881262135404653, 51.56204012483733], [-0.881418631531618, 51.562011943580096], [-0.881649213834679, 51.56196288783239], [-0.882003250428868, 51.56187993977645], [-0.882376388095226, 51.56178278572967], [-0.882764299497775, 51.56167138432022], [-0.883194585739291, 51.561537905452155], [-0.883498576630078, 51.5614364931922], [-0.883756281221724, 51.56134003501421], [-0.884086956514705, 51.56120920221847], [-0.884407665982054, 51.56107287871968], [-0.885457870533961, 51.5606602434964], [-0.885606584631741, 51.56059601575753], [-0.88578613479336, 51.56050960117672], [-0.88595858283258, 51.56041862303493], [-0.886091760097573, 51.560340759581955], [-0.886521253482028, 51.56006159461465], [-0.886883345687433, 51.559824949307504], [-0.887389733197074, 51.559468282123994], [-0.887580604245187, 51.55927227271282], [-0.887708691217493, 51.559107139161064], [-0.888191015763102, 51.55861266662589], [-0.888192457957821, 51.55861268028735], [-0.888287760756616, 51.55849039596854], [-0.888562664893145, 51.558278995716826], [-0.888677108662246, 51.55814070717499], [-0.888887527216288, 51.55791161122132], [-0.889030158653071, 51.55774121885465], [-0.889203011709727, 51.557514464273005], [-0.88945350380216, 51.55717964382524], [-0.889600043815338, 51.556967026485395], [-0.889736358446423, 51.55670036168757], [-0.889858423154084, 51.55648571413559], [-0.889957478394766, 51.55626815130874], [-0.88999480235023, 51.556157006507235], [-0.890171676314085, 51.5555274577222], [-0.89040150985715, 51.554855248874496], [-0.891496918227321, 51.55316795557777], [-0.892148150167392, 51.55212836271704], [-0.892302414411729, 51.5517746441604], [-0.892679622502675, 51.55097074336506], [-0.892968782461996, 51.55046633574481], [-0.893655961353766, 51.54930928124159], [-0.894173495307085, 51.548604708475054], [-0.894625223197592, 51.54805597035748], [-0.895275002004698, 51.547308578527485], [-0.895581553072133, 51.54691762432374], [-0.89567259455686, 51.54679079793778], [-0.895853734572665, 51.54651645501248], [-0.896746527292651, 51.54508077321264], [-0.896901839906062, 51.544860136456265], [-0.897255891587921, 51.54494888564188], [-0.898115394177492, 51.545187148067974], [-0.89822539056202, 51.54523044209882], [-0.898280925208036, 51.54525973711452], [-0.898317695099433, 51.54528975512979], [-0.898473190139101, 51.54530020648797], [-0.899619101095523, 51.54544313546729], [-0.901006352145532, 51.54562517973134], [-0.901825064903737, 51.54570208025918], [-0.903152296119515, 51.54586195719927], [-0.903215411109321, 51.54587603470979], [-0.903297183099556, 51.545893883241035], [-0.903017403675823, 51.54655396139701], [-0.902616538461231, 51.54745118838641], [-0.902395351374664, 51.54801290343283], [-0.902224993241029, 51.54837997226972], [-0.902166365216381, 51.54859882282856], [-0.902146545476892, 51.54876318664974], [-0.902208891983797, 51.54892921824649], [-0.902230894835185, 51.549033728477525], [-0.902380735585514, 51.54999904656443], [-0.902673692529055, 51.551610411429984], [-0.902806620567669, 51.55250003963136], [-0.902816651036337, 51.55268266601908], [-0.902804979597758, 51.55292803179951], [-0.902756997764027, 51.55318384821566], [-0.902654701329301, 51.55353896524768], [-0.902427419928527, 51.55423280167036], [-0.901847751389036, 51.555843197130926], [-0.901770133963284, 51.556011515784924], [-0.90172081219273, 51.556082988265544], [-0.902203201151337, 51.55617741874876], [-0.906010818638152, 51.55679743475821], [-0.906204734572883, 51.556771367660915], [-0.906311884484255, 51.55675438267928], [-0.906358975073264, 51.55689599188705], [-0.90638590166065, 51.55691602462513], [-0.906615524939952, 51.55696492104195], [-0.907278267614382, 51.55705831304524], [-0.907858939004531, 51.55720578727805], [-0.908174621569804, 51.5572752632291], [-0.908339760107985, 51.55730647205926], [-0.908420198492941, 51.557320707807335], [-0.908923514869315, 51.557385632424236], [-0.909322889103033, 51.5574540848968], [-0.909506497855653, 51.557497152980005], [-0.909658336207082, 51.557541723987356], [-0.909754316957776, 51.55756959081508], [-0.909871264277585, 51.557625526703404], [-0.91002439519459, 51.55767640345812], [-0.91014009429463, 51.557724234915874], [-0.910363938659539, 51.55783421414451], [-0.910769828656022, 51.55805288423369], [-0.910899633150579, 51.55817457810929], [-0.911134211672749, 51.55843931338367], [-0.911191431662737, 51.558519870694006], [-0.911262279817118, 51.55863382382822], [-0.911345597527786, 51.558829717406], [-0.911347039740573, 51.55882973078292], [-0.911354152248679, 51.55895478193117], [-0.911501156990394, 51.55932300828838], [-0.911744284152759, 51.55977395051585], [-0.911784714781588, 51.55983277167005], [-0.911848028397377, 51.559899897522016], [-0.911951124589094, 51.55999256899618], [-0.912043240814804, 51.56006176008463], [-0.912343203354435, 51.560247072388215], [-0.91252735254784, 51.560389049785144], [-0.912663001694362, 51.56050809825428], [-0.913644040185922, 51.561715780647766], [-0.914729932802775, 51.56149024267299], [-0.915936249212879, 51.561720788632314], [-0.917099342153636, 51.56255696600573], [-0.917716153850379, 51.56209778262442], [-0.918510926061236, 51.561494569835055], [-0.919190082061234, 51.56187308324347], [-0.919265061021478, 51.56187467281339], [-0.919319677161742, 51.561883268238525], [-0.919395565855925, 51.56190734542486], [-0.919450182060758, 51.561915940789575], [-0.919451624375034, 51.56191595406745], [-0.919612764956992, 51.561873377936905], [-0.919684473323871, 51.562134798108005], [-0.919731696029427, 51.56227280618616], [-0.919795125391412, 51.562396576626476], [-0.919877773921036, 51.56250074208832], [-0.920024454979703, 51.56264236275641], [-0.920273793481437, 51.562835281288635], [-0.920455811890565, 51.56300779833283], [-0.92054707457537, 51.56311384087594], [-0.920622684574115, 51.56321074767881], [-0.920768557091237, 51.56344767224896], [-0.920815933327546, 51.56357938704838], [-0.92087756775181, 51.56365728255545], [-0.920897207761338, 51.56368084160506], [-0.920950783915168, 51.5637334861553], [-0.921113636188415, 51.563862665653886], [-0.921195103215065, 51.56395602921301], [-0.921351882125165, 51.56422002842434], [-0.921395592904906, 51.56432383493418], [-0.921420893006769, 51.56441308549212], [-0.921438619701684, 51.56451755238376], [-0.921413985191466, 51.56464410933019], [-0.92167481147157, 51.56453500840272], [-0.923479752756133, 51.56373602685831], [-0.924155377789785, 51.5634113259626], [-0.924873111301507, 51.56399247344971], [-0.924951149378637, 51.56404803772923], [-0.925274524870032, 51.56428388466152], [-0.92664770764064, 51.56515336065692], [-0.927393574791524, 51.56558368874587], [-0.927927453464337, 51.5659491340051], [-0.92835633038721, 51.56599441223158], [-0.928244524844939, 51.56725223174753], [-0.928125342518282, 51.56741209518939], [-0.9281054698832, 51.56745956981058], [-0.927839528670842, 51.568092855254655], [-0.93052584537502, 51.568532778436946], [-0.930434864440691, 51.56872077542371], [-0.930290537945866, 51.568968530677175], [-0.93032458943141, 51.568993118606556], [-0.930407160146686, 51.56904062792432], [-0.930494248489543, 51.56908008580425], [-0.93056005729139, 51.5691040638391], [-0.930644619283805, 51.56912821268005], [-0.930755210497826, 51.569149901051155], [-0.931002865082897, 51.56917193845677], [-0.931506345671459, 51.5692367670135], [-0.9319179887186, 51.56928007686346], [-0.93222706378822, 51.569328746497334], [-0.932389335623021, 51.56936169347699], [-0.932508352034028, 51.56939334769875], [-0.932608510110525, 51.56942932617174], [-0.932871163025979, 51.56955040480943], [-0.933086053531851, 51.569616199317096], [-0.933414865356232, 51.569684826955594], [-0.93386895042082, 51.56976448240679], [-0.934635570791928, 51.5700537823344], [-0.934785550106084, 51.57011898456062], [-0.934985327167408, 51.57021431104797], [-0.935122135234023, 51.5702874858722], [-0.935333952219633, 51.570423383659445], [-0.935683954424458, 51.570697207984594], [-0.935948857561102, 51.57084617434456], [-0.936321009353978, 51.57109861741231], [-0.936776166293208, 51.57138058458356], [-0.936874033955222, 51.57139136186155], [-0.937185388877335, 51.57140497135624], [-0.937358713203379, 51.57139754881963], [-0.937474500211682, 51.571382411871916], [-0.937604964789291, 51.57135661760672], [-0.938082770631526, 51.571224267138255], [-0.938303744516349, 51.57115343316592], [-0.938622419406116, 51.57103852370375], [-0.938583754985448, 51.57127375671787], [-0.938615426417796, 51.5714008261012], [-0.938651384040882, 51.57152973256723], [-0.938810396393867, 51.572013125409214], [-0.938917102284257, 51.5723881447753], [-0.938977920287056, 51.572564931845086], [-0.939147081147104, 51.57298457478389], [-0.93921529881351, 51.57340150695511], [-0.939295227462625, 51.57374930879435], [-0.939359853061118, 51.57401065198471]]]}}
+ test/json-data/integers.json view
@@ -0,0 +1,1 @@+[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 26, 27, 29, 31, 33, 35, 37, 39, 42, 44, 47, 50, 53, 56, 60, 63, 67, 72, 76, 81, 86, 91, 96, 102, 109, 115, 122, 130, 138, 146, 155, 165, 175, 186, 197, 209, 222, 236, 250, 266, 282, 299, 318, 337, 358, 380, 403, 428, 454, 482, 511, 543, 576, 611, 649, 688, 730, 775, 823, 873, 926, 983, 1043, 1107, 1175, 1247, 1323, 1404, 1490, 1582, 1679, 1781, 1890, 2006, 2129, 2259, 2398, 2544, 2700, 2865, 3041, 3227, 3425, 3634, 3857, 4093, 4343, 4609, 4891, 5191, 5509, 5846, 6204, 6583, 6986, 7414, 7868, 8349, 8860, 9403, 9978, 10589, 11237, 11925, 12655, 13430, 14252, 15124, 16050, 17032, 18075, 19181, 20355, 21601, 22923, 24326, 25815, 27396, 29072, 30852, 32740, 34744, 36871, 39128, 41523, 44064, 46762, 49624, 52661, 55884, 59305, 62935, 66787, 70875, 75213, 79817, 84702, 89887, 95389, 101227, 107423, 113998, 120976, 128381, 136239, 144578, 153427, 162818, 172784, 183360, 194583, 206493, 219132, 232545, 246778, 261883, 277912, 294923, 312975, 332131, 352460, 374034, 396928, 421223, 447005, 474365, 503400, 534212, 566911, 601610, 638433, 677511, 718980, 762987, 809688, 859247, 911840, 967652, 1026880, 1089734, 1156434, 1227217, 1302333, 1382046, 1466638, 1556408, 1651673, 1752769, 1860052, 1973902, 2094721, 2222934, 2358996, 2503385, 2656613, 2819219, 2991777, 3174898, 3369227, 3575451, 3794297, 4026539, 4272995, 4534536, 4812086, 5106625, 5419191, 5750889, 6102889, 6476435, 6872845, 7293518, 7739939, 8213686, 8716429, 9249944, 9816115, 10416939, 11054539, 11731166, 12449207, 13211198, 14019829, 14877955, 15788605, 16754994, 17780533, 18868844, 20023768, 21249383, 22550016, 23930257, 25394980, 26949356, 28598872, 30349352, 32206975, 34178300, 36270285, 38490317, 40846232, 43346349, 45999492, 48815029, 51802899, 54973651, 58338478, 61909260, 65698602, 69719882, 73987297, 78515911, 83321713, 88421668, 93833782, 99577160, 105672079, 112140056, 119003924, 126287916, 134017747, 142220706, 150925751, 160163614, 169966908, 180370243, 191410345, 203126189, 215559137, 228753081, 242754599, 257613123, 273381107, 290114218, 307871529, 326715729, 346713346, 367934976, 390455540, 414354543, 439716356, 466630515, 495192035, 525501749, 557666661, 591800322, 628023236, 666463282, 707256166, 750545902, 796485316, 845236589, 896971830, 951873682, 1010135966, 1071964368, 1137577163, 1207205986, 1281096650, 1359510014, 1442722903, 1531029087, 1624740315, 1724187420, 1829721484, 1941715077, 2060563573, 2186686548, 2320529259, 2462564214, 2613292844, 2773247272, 2942992191, 3123126858, 3314287206, 3517148098, 3732425698, 3960880011, 4203317554, 4460594215, 4733618266, 5023353573, 5330822998, 5657112012, 6003372524, 6370826950, 6760772526, 7174585891, 7613727944, 8079749004, 8574294281, 9099109685, 9656047991, 10247075377, 10874278366, 11539871197, 12246203633, 12995769265, 13791214310, 14635346955, 15531147272, 16481777734, 17490594386, 18561158687, 19697250088, 20902879371, 22182302812, 23540037202, 24980875800, 26509905246, 28132523526, 29854459026, 31681790754, 33620969802, 35678842122, 37862672691, 40180171161, 42639519077, 45249398761, 48019023960, 50958172379, 54077220194, 57387178688, 60899733121, 64627283986, 68582990784, 72780818484, 77235586822, 81963022620, 86979815309, 92303675844, 97953399235, 103948930895, 110311437058, 117063379497, 124228594829, 131832378662, 139901574895, 148464670491, 157551896043, 167195332496, 177429024407, 188289100133, 199813899374, 212044108527, 225022904322, 238796106249, 253412338321, 268923200725, 285383451995, 302851202324, 321388118716, 341059642687, 361935221296, 384088552321, 407597844432, 432546093294, 459021374572, 487117154867, 516932621682, 548573033590, 582150091830, 617782334651, 655595555791, 695723248569, 738307077168, 783497376747, 831453684183, 882345301285, 936351892486, 993664119121, 1054484312524, 1119027188325, 1187520604468, 1260206365627, 1337341076854, 1419197049486, 1506063262491, 1598246382662, 1696071847252, 1799885012878, 1910052374747, 2026962860500, 2151029203266, 2282689398739, 2422408251457, 2570679015712, 2728025136906, 2895002099486, 3072199387991, 3260242568131, 3459795495242, 3671562657914, 3896291665080, 4134775885316, 4387857247705, 4656429214122, 4941439933460, 5243895588908, 5564863950114, 5905478142772, 6266940648935, 6650527552175, 7057593042589, 7489574197539, 7947996055022, 8434476997558, 8950734465625, 9498591020797, 10079980779998, 10696956243580, 11351695541337, 12046510122031, 12783852913581, 13566326982715, 14396694724673, 15277887615381, 16213016560543, 17205382878181, 18258489953389, 19376055606456, 20562025218016, 21820585657560, 23156180064488, 24573523533875, 26077619762337, 27673778712750, 29367635360200, 31165169585327, 33072727285306, 35097042776985, 37245262571278, 39524970602741, 41944215003394, 44511536515321, 47235998642351, 50127219647252, 53195406507421, 56451390948928, 59906667686130, 63573435001862, 67464637811456, 71594013362620, 75976139732519, 80626487293267, 85561473327514, 90798519986944, 96356115798305, 102253880934088, 108512636478302, 115154477931865, 122202853217119, 129682645456833, 137620260819954, 146043721744222, 154982765864743, 164468950997792, 174535766550465, 185218751749486, 196555621106568, 208586397563259, 221353553785311, 234902162105402, 249280053643550, 264537987166964, 280729828285480, 297912739615178, 316147382581544, 335498131574595, 356033301212013, 377825387512598, 400951323831468, 425492752460545, 451536312853150, 479173947490266, 508503226468250, 539627691953919, 572657223723034, 607708427072674, 644905044476938, 684378392439283, 726267825083707, 770721226121430, 817895530929871, 867957280587026, 921083209817197, 977460870923688, 1037289295911185, 1100779699135317, 1168156222959992, 1239656729054927, 1315533638126921, 1396054821049394, 1481504544536185, 1572184474698156, 1668414742025481, 1770535071555377, 1878905982215138, 1993910059574563, 2115953306501003, 2245466576485316, 2382907094698829, 2528760072151156, 2683540418647385, 2847794560591953]
+ test/json-data/jp10.json view
@@ -0,0 +1,1 @@+{"results":[{"from_user_id_str":"2458313","profile_image_url":"http://a2.twimg.com/profile_images/1203653060/fure091226_normal.png","created_at":"Thu, 27 Jan 2011 20:30:04 +0000","from_user":"19princess","id_str":"30724239224995840","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6d77\u6674\u300c\u672c\u65e5\u306e\u6771\u4eac\u306e\u304a\u5929\u6c17\u306f\u6674\u6642\u3005\u66c7\u3067\u3057\u3087\u3046\u3002\u6700\u9ad8\u6c17\u6e29\u306f8\u5ea6\u3001\u6700\u4f4e\u6c17\u6e29\u306f1\u5ea6\u3067\u3059\u3002\u3042\u306a\u305f\u306e\u4eca\u65e5\u306e\u4eba\u751f\u306b\u3068\u3073\u3063\u304d\u308a\u306e\u304a\u5929\u6c17\u3092\u2665\u300d","id":30724239224995840,"from_user_id":2458313,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://babyprincess.sakura.ne.jp/about/&quot; rel=&quot;nofollow&quot;&gt;\u5929\u4f7f\u5bb6\u306e\u88cf\u5c71&lt;/a&gt;"},{"from_user_id_str":"66578965","profile_image_url":"http://a0.twimg.com/profile_images/1183763267/fossetta_normal.png","created_at":"Thu, 27 Jan 2011 20:00:04 +0000","from_user":"Fossetta_Tokyo","id_str":"30716689779785729","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u304a\u306f\u3088\u3046\u3054\u3056\u3044\u307e\u3059!!\u6771\u4eac\u90fd\u3001\u672c\u65e5\u306e\u304a\u5929\u6c17\u306f\u6674\u6642\u3005\u66c7\u3002\u6700\u9ad8\u6c17\u6e298\u5ea6\u3001\u6700\u4f4e\u6c17\u6e291\u5ea6\u3002\u6771\u4eac\u5730\u65b9\u3067\u306f\u3001\u7a7a\u6c17\u306e\u4e7e\u71e5\u3057\u305f\u72b6\u614b\u304c\u7d9a\u3044\u3066\u3044\u307e\u3059\u3002\u706b\u306e\u53d6\u308a\u6271\u3044\u306b\u6ce8\u610f\u3057\u3066\u4e0b\u3055\u3044\u3002\u4f0a\u8c46\u8af8\u5cf6\u3068\u5c0f\u7b20\u539f\u8af8\u5cf6\u306b\u306f\u3001\u5f37\u98a8\u3001\u6ce2\u6d6a\u3001\u4e7e\u71e5\u3001\u971c\u306e\u6ce8\u610f\u5831\u3092\u767a\u8868\u4e2d\u3067\u3059\u3002","id":30716689779785729,"from_user_id":66578965,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://bit.ly/Fossetta&quot; rel=&quot;nofollow&quot;&gt;\u30d5\u30a9\u30bb\u30c3\u30bf ver.3.1.1&lt;/a&gt;"},{"from_user_id_str":"104041146","profile_image_url":"http://a2.twimg.com/profile_images/863965118/001jwatokyo_normal.jpg","created_at":"Thu, 27 Jan 2011 19:44:33 +0000","from_user":"jwa_tokyo","id_str":"30712787537756160","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6c17\u8c61\u5e81\u304b\u3089\u6771\u4eac\u306e\u5929\u6c17\u4e88\u5831\u304c\u767a\u8868\u3055\u308c\u307e\u3057\u305f\u3000\u305d\u306e\u5929\u6c17\u4e88\u5831\u3092\u3053\u3053\u3067\u3064\u3076\u3084\u3053\u3046\u304b\u306a\u3041\uff5e\uff1f\u3000\u8003\u3048\u4e2d\u3000\u307e\u3066\u6b21\u53f7\uff08\u7b11","id":30712787537756160,"from_user_id":104041146,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.docodemo.jp/twil/&quot; rel=&quot;nofollow&quot;&gt;Twil2 (Tweet Anytime, Anywhere by Mail)&lt;/a&gt;"},{"from_user_id_str":"144500192","profile_image_url":"http://a3.twimg.com/a/1294874399/images/default_profile_3_normal.png","created_at":"Thu, 27 Jan 2011 18:59:33 +0000","from_user":"kyo4to4","id_str":"30701462774358016","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u90fd \u516b\u4e08\u5cf6 - \u4eca\u65e5\u306e\u5929\u6c17\u306f\u30fb\u30fb\u30fb\u66c7\u306e\u3061\u6674\u3067\u3059\u306e\uff01","id":30701462774358016,"from_user_id":144500192,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/kyo4to4&quot; rel=&quot;nofollow&quot;&gt;lost-sheep-bot&lt;/a&gt;"},{"from_user_id_str":"165724582","profile_image_url":"http://a0.twimg.com/profile_images/1222842347/163087_1256281064506_1753997852_484926_2761052_n_normal.jpg","created_at":"Thu, 27 Jan 2011 17:39:06 +0000","from_user":"Rifqi_19931020","id_str":"30681213748387840","metadata":{"result_type":"recent"},"to_user_id":113796067,"text":"@CHLionRagbaby \u30b1\u30f3\u3061\u3083\u3093\u3001\u671d\u4eca\u307e\u3067\u306e\u81ea\u5206\u306e\u30db\u30fc\u30e0\u30a8\u30ea\u30a2\u304b\u3089\u307e\u3060\u975e\u5e38\u306b\u5bd2\u3044\u3068\u96e8\u304c\u964d\u3063\u3066\u3044\u305f..\u3069\u306e\u3088\u3046\u306b\u73fe\u5728\u306e\u6771\u4eac\u306e\u5929\u6c17\uff1f","id":30681213748387840,"from_user_id":165724582,"to_user":"CHLionRagbaby","geo":null,"iso_language_code":"ja","to_user_id_str":"113796067","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"120911929","profile_image_url":"http://a0.twimg.com/profile_images/772435076/20100312___capture2_normal.png","created_at":"Thu, 27 Jan 2011 17:28:30 +0000","from_user":"Cirno_fan","id_str":"30678546020040705","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4eca\u65e5\u306e\u6771\u4eac\u306e\u5929\u6c17\u306f\u3001\u66c7\u6642\u3005\u6674\u3067\u6700\u9ad8\u6c17\u6e29\u306f8\u2103\uff01 \u6700\u4f4e\u6c17\u6e29\u306f2\u2103\u3060\u3063\u305f\u3088\uff01 RT @mimi22999 \uff08\uff65\u2200\uff65\uff09\uff4c\u3001\u865a\u5f31\u306a\u8005\u306b\u3068\u3063\u3066\u3001\u6717\u3089\u304b\u306a\u9854\u306f\u4e0a\u5929\u6c17\u3068\u540c\u3058\u304f\u3089\u3044\u3046\u308c\u3057\u3044\u3082\u306e\u3060\u3002\u30d5\u30e9\u30f3\u30af\u30ea\u30f3 #tenki #bot","id":30678546020040705,"from_user_id":120911929,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://blog.livedoor.jp/fairycirno/archives/34686.html&quot; rel=&quot;nofollow&quot;&gt;\u5e7b\u60f3\u90f7 \u9727\u306e\u6e56&lt;/a&gt;"},{"from_user_id_str":"65976527","profile_image_url":"http://a0.twimg.com/profile_images/452810990/little_italies_____normal.jpg","created_at":"Thu, 27 Jan 2011 17:00:03 +0000","from_user":"heta_weather01","id_str":"30671388754845696","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3010\u30d8\u30bf\u5929\u3011Tere hommikust.\u30a8\u30b9\u30c8\u30cb\u30a2\u3067\u3059\u3002\u4eca\u65e5\u306e\u6771\u4eac\u306e\u5929\u6c17\u306f\u6674\u6642\u3005\u66c7\u3067\u660e\u65e5\u306f\u66c7\u308a\u3067\u3059\u3002\u3061\u306a\u307f\u306b\u50d5\u306e\u3068\u3053\u308d\u3067\u306f\u66c7\u308a\u3067\u6c17\u6e29-7\u2103\u3067\u3059\u3002\u3061\u306a\u307f\u306b\u30b9\u30ab\u30a4\u30d7\u306e\u958b\u767a\u672c\u90e8\u306f\u50d5\u306e\u5bb6\u306b\u3042\u308b\u3093\u3067\u3059\u3002","id":30671388754845696,"from_user_id":65976527,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www15.atpages.jp/~kageyanma/&quot; rel=&quot;nofollow&quot;&gt;\u5730\u7403\u306e\u4e2d&lt;/a&gt;"},{"from_user_id_str":"7278433","profile_image_url":"http://a3.twimg.com/profile_images/1218965303/michael-1_normal.png","created_at":"Thu, 27 Jan 2011 16:50:16 +0000","from_user":"shimohiko","id_str":"30668926035689472","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3042\u308a\u3002\n\u3010\u7f8e\u4eba\u5929\u6c17/\u6771\u4eac\u3011\u7f8e\u4eba\u5929\u6c17\u30ad\u30e3\u30b9\u30bf\u30fc\u306e&quot;\u3055\u3042\u3084\u3093\u3055\u3093&quot;\u306b\u3088\u308b\u3068\u300c1/29(\u571f)\u306f\u304f\u3082\u308a\u3067\u3001\u964d\u6c34\u78ba\u738740%\u3001\u6700\u9ad8\u6c17\u6e29\u306f6\u2103\u3067\u6700\u4f4e\u6c17\u6e29\u306f1\u2103\u3067\u3059\u300d\u7f8e\u4eba\u5929\u6c17\u21d2http://bit.ly/djB8th http://twitpic.com/3twnl0 #bt_tenki","id":30668926035689472,"from_user_id":7278433,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://bijintenki.jp&quot; rel=&quot;nofollow&quot;&gt;bijintenki.jp&lt;/a&gt;"},{"from_user_id_str":"61770","profile_image_url":"http://a3.twimg.com/profile_images/1206955079/tw172a_normal.png","created_at":"Thu, 27 Jan 2011 16:40:52 +0000","from_user":"rsky","id_str":"30666561853333504","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3075\u3068\u591c\u7a7a\u3092\u898b\u4e0a\u3052\u3066\u30aa\u30ea\u30aa\u30f3\u304c\u898b\u3048\u306a\u304f\u3066\u300c\u6771\u4eac\u306b\u306f\u7a7a\u304c\u306a\u3044\u300d\u3068\u667a\u6075\u5b50\u306e\u3088\u3046\u306a\u3053\u3068\u3092\u601d\u3063\u305f\u308f\u3051\u3060\u304c\u3001\u305f\u3076\u3093\u534a\u5206\u3050\u3089\u3044\u306f\u5929\u6c17\u306e\u305b\u3044\u3067\u3059","id":30666561853333504,"from_user_id":61770,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"103259265","profile_image_url":"http://a0.twimg.com/profile_images/767857973/anime_icon_normal.gif","created_at":"Thu, 27 Jan 2011 16:37:42 +0000","from_user":"liveshowonly","id_str":"30665765698928640","metadata":{"result_type":"recent"},"to_user_id":null,"text":"iPhone\u5929\u6c17\u3002\u6771\u4eac4\u2103\u3063\u3066\u7d50\u69cb\u5bd2\u304f\u306a\u3044\u3058\u3083\u3093\u3002\uff08\u78ba\u304b\u306b\u3082\u306e\u51c4\u304f\u5bd2\u3044\u8a33\u3067\u306f\u7121\u3044\uff09\u3002\u798f\u5ca1\u5e02\u306f1\u2103\u3060\u3002\u52dd\u3061\u3060\u305c\u3002Rock'n'roll","id":30665765698928640,"from_user_id":103259265,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"165242761","profile_image_url":"http://a1.twimg.com/profile_images/1147334744/SN3E00600001_normal.jpg","created_at":"Thu, 27 Jan 2011 16:37:35 +0000","from_user":"deuxavril0502","id_str":"30665736556912640","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6b8b\u5ff5\u3001\u79c1\u306f\u6c96\u7e04\u3067\u3059(&gt;_&lt;)\u3067\u3082\u304a\u5929\u6c17\u826f\u3055\u305d\u3046\u3067\u826f\u304b\u3063\u305f\u306d\u3002\u3053\u3061\u3089\u306f\u96e8\u3088\uff5eRT @rinandy2010: \u305d\u3046\u3067\u3059\u3063\u266a\u51fa\u5f35\u3067(^^)\u304a\u306d\u3048\u3055\u307e\u306f\u6771\u4eac\u3067\u3059\u304b\uff1f\u3081\u3063\u3061\u3083\u5929\u6c17\u826f\u304f\u3066\u3073\u3063\u304f\u308a\u3067\u3059\u3002\u624b\u888b\u3068\u304b\u5168\u7136\u3044\u3089\u306a\u3044\u3067\u3059\u306d\u30fc RT @deuxavril0502 \u6771\u4eac\u306a\u306e\u30fc\uff1f","id":30665736556912640,"from_user_id":165242761,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.echofon.com/&quot; rel=&quot;nofollow&quot;&gt;Echofon&lt;/a&gt;"},{"from_user_id_str":"163900288","profile_image_url":"http://a1.twimg.com/profile_images/1210224823/icon12945064955238_normal.jpg","created_at":"Thu, 27 Jan 2011 16:24:37 +0000","from_user":"nyao_yurichan","id_str":"30662472734089216","metadata":{"result_type":"recent"},"to_user_id":100985873,"text":"@ray_ko302 \u767a\u898b\u3042\u308a\u304c\u3068\u3067\u3059\u3045\u3002\u3053\u3061\u3089\u3067\u3082\u3088\u308d\u3057\u304f\u306d\u3002\u6771\u4eac\u306f\u4eca\u65e5\u3082\u4e7e\u71e5\u3067\u5927\u5909\u3088\u3002\u305d\u3063\u3061\u3068\u771f\u9006\u306e\u5929\u6c17\u3060\u306d\u3002\u30a2\u30a4\u30b9\u30d0\u30fc\u30f3\u304d\u3092\u3064\u3051\u3066\u3088\u306d\u3002","id":30662472734089216,"from_user_id":163900288,"to_user":"ray_ko302","geo":null,"iso_language_code":"ja","to_user_id_str":"100985873","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"49227098","profile_image_url":"http://a3.twimg.com/profile_images/965007882/____normal.jpg","created_at":"Thu, 27 Jan 2011 15:52:26 +0000","from_user":"dosannko6","id_str":"30654371016478720","metadata":{"result_type":"recent"},"to_user_id":108570870,"text":"@peke_hajiP \u4ffa\u304c\u6771\u4eac \u6765\u3066\u6700\u521d\u306b\u9a5a\u3044\u305f\u306e\u304c\u3001\u5929\u6c17\u4e88\u5831\u3067\u82b1\u7c89\u60c5\u5831\u304c\u6d41\u308c\u308b\u3053\u3068\u3067\u3001\u6700\u521d\u306b\u8a66\u3057\u305f\u306e\u304c \u30b4\u30ad\u69d8 \u53ec\u559a\u306e\u5100\u5f0f\u3067\u3059\u304a\uff1f","id":30654371016478720,"from_user_id":49227098,"to_user":"peke_hajip","geo":null,"iso_language_code":"ja","to_user_id_str":"108570870","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"71148934","profile_image_url":"http://a0.twimg.com/profile_images/1209223630/image_normal.jpg","created_at":"Thu, 27 Jan 2011 15:46:49 +0000","from_user":"123keiko","id_str":"30652958311981058","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u9727\u5cf6\u306e\u964d\u7070\u306e\u30cb\u30e5\u30fc\u30b9\u3092\u898b\u3066\u601d\u3044\u51fa\u3057\u307e\u3057\u305f\u3002\u4e0a\u4eac\u3057\u305f\u59cb\u3081\u306e\u9803\u3001\u6771\u4eac\u306f1\u5e74\u4e2d\u3001\u7070\u304c\u964d\u3089\u306a\u3044\u304b\u3089\u7a7a\u6c17\u304c\u6f84\u3093\u3067\u3066\u904e\u3054\u3057\u3084\u3059\u3044\u306a\u3041\u3001\u3068\u601d\u3063\u305f\u306a\u3041\u3001\u3063\u3066\u3002\n\u5b9f\u5bb6\u306f\u51ac\u306e\u5b63\u7bc0\u98a8\u3067\u685c\u5cf6\u306e\u7070\u304c\u964d\u308b\u5730\u533a\u3067\u3057\u305f\u3002\u9e7f\u5150\u5cf6\u306e\u5929\u6c17\u4e88\u5831\u3067\u306f\u3001\u6bce\u65e5\u3001\u685c\u5cf6\u4e0a\u7a7a\u306e\u98a8\u5411\u304d\u4e88\u5831\u304c\u3067\u307e\u3059\u3002\u3053\u308c\u304b\u3089\u306f\u9727\u5cf6\u3082\u304b\u306a\uff1f","id":30652958311981058,"from_user_id":71148934,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"91124773","profile_image_url":"http://a3.twimg.com/profile_images/1139308356/prof101007_3-1_normal.jpg","created_at":"Thu, 27 Jan 2011 15:43:35 +0000","from_user":"sanposuruhito","id_str":"30652146277945345","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4eca\u5bb5\u306e\u90fd\u5fc3\u306f\u3001\u8eab\u3082\u5f15\u304d\u7de0\u307e\u308b\u3068\u3044\u3046\u3088\u308a\u306f\u51cd\u3048\u308b\u7a0b\u306e\u51b7\u6c17\u3092\u611f\u3058\u308b\u5bd2\u3044\u591c\u3067\u3059\u3002\u660e\u65e5\u65e5\u4e2d\u306e\u6771\u4eac\u306e\u5929\u6c17\u306f\u3001\u5915\u65b9\u306b\u591a\u5c11\u96f2\u304c\u51fa\u308b\u5834\u6240\u304c\u3042\u308a\u305d\u3046\u306a\u3082\u306e\u306e\u6982\u306d\u6674\u308c\u7a7a\u304c\u5e83\u304c\u308a\u7d9a\u3051\u305d\u3046\u3067\u3059\u3002\u6700\u9ad8\u6c17\u6e29\u306f\u30015-6\u5ea6\u4f4d\u3068\u306a\u308a\u305d\u3046\u3067\u3059\u3002#weather_tokyo","id":30652146277945345,"from_user_id":91124773,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://projects.playwell.jp/go/Saezuri&quot; rel=&quot;nofollow&quot;&gt;Saezuri&lt;/a&gt;"}],"max_id":30724239224995840,"since_id":28179956995457024,"refresh_url":"?since_id=30724239224995840&q=%E6%9D%B1%E4%BA%AC%E3%80%80%E5%A4%A9%E6%B0%97","next_page":"?page=2&max_id=30724239224995840&lang=ja&q=%E6%9D%B1%E4%BA%AC%E3%80%80%E5%A4%A9%E6%B0%97","results_per_page":15,"page":1,"completed_in":0.104827,"warning":"adjusted since_id to 28179956995457024 (), requested since_id was older than allowed -- since_id removed for pagination.","since_id_str":"28179956995457024","max_id_str":"30724239224995840","query":"%E6%9D%B1%E4%BA%AC%E3%80%80%E5%A4%A9%E6%B0%97"}
+ test/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":"&lt;a href=&quot;http://twipple.jp/&quot; rel=&quot;nofollow&quot;&gt;\u3064\u3044\u3063\u3077\u308b for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://proory.com/&quot; rel=&quot;nofollow&quot;&gt;proory tems&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.flight.co.jp/iPhone/TweetMe/&quot; rel=&quot;nofollow&quot;&gt;TweetMe for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.movatwi.jp&quot; rel=&quot;nofollow&quot;&gt;www.movatwi.jp&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://jigtwi.jp/?p=1&quot; rel=&quot;nofollow&quot;&gt;jigtwi&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.flight.co.jp/iPhone/TweetMe/&quot; rel=&quot;nofollow&quot;&gt;TweetMe for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twtr.jp&quot; rel=&quot;nofollow&quot;&gt;Keitai Web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.nibirutech.com/&quot; rel=&quot;nofollow&quot;&gt;TwitBird iPad&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://z.twipple.jp/&quot; rel=&quot;nofollow&quot;&gt;\u3064\u3044\u3063\u3077\u308b/twipple&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://blog.seesaa.jp/&quot; rel=&quot;nofollow&quot;&gt;SeesaaBlog&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://blog.seesaa.jp/&quot; rel=&quot;nofollow&quot;&gt;SeesaaBlog&lt;/a&gt;"},{"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&amp;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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://cheebow.info/chemt/archives/2007/04/twitterwindowst.html&quot; rel=&quot;nofollow&quot;&gt;Twit for Windows&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.twitter.com/ReajuBreaker&quot; rel=&quot;nofollow&quot;&gt;\u73fe\u5145\u6bba\u3057\u306e\u7121\u4eba\u9023\u545f\uff1c\u30aa\u30fc\u30c8\u30c4\u30a4\u30fc\u30c8\uff1e&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://z.twipple.jp/&quot; rel=&quot;nofollow&quot;&gt;\u3064\u3044\u3063\u3077\u308b/twipple&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twipple.jp/&quot; rel=&quot;nofollow&quot;&gt;\u3064\u3044\u3063\u3077\u308b for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://stone.com/Twittelator&quot; rel=&quot;nofollow&quot;&gt;Twittelator&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://projects.playwell.jp/go/Saezuri&quot; rel=&quot;nofollow&quot;&gt;Saezuri&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://z.twipple.jp/&quot; rel=&quot;nofollow&quot;&gt;\u3064\u3044\u3063\u3077\u308b/twipple&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www20.atpages.jp/neoneko/&quot; rel=&quot;nofollow&quot;&gt;neoneko_bot5&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://777labo.com/mychecker/&quot; rel=&quot;nofollow&quot;&gt;MYCHEBOT&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"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 &quot;Twitter\u306e2\u30c1\u30e3\u30f3\u30cd\u30eb\u5316\u306f\u9632\u6b62\u51fa\u6765\u308b\u304b&quot; http://t.co/Mwzb8Zf","id":41190306145775617,"from_user_id":11111695,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twibow.net/&quot; rel=&quot;nofollow&quot;&gt;Twibow&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.teramax.jp/aboutus.html&quot; rel=&quot;nofollow&quot;&gt;tmxbot&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.echofon.com/&quot; rel=&quot;nofollow&quot;&gt;Echofon&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://seesmic.com/seesmic_desktop/sd2&quot; rel=&quot;nofollow&quot;&gt;Seesmic Desktop&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twittbot.net/&quot; rel=&quot;nofollow&quot;&gt;twittbot.net&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://seesmic.com/seesmic_desktop/sd2&quot; rel=&quot;nofollow&quot;&gt;Seesmic Desktop&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twipple.jp/&quot; rel=&quot;nofollow&quot;&gt;\u3064\u3044\u3063\u3077\u308b for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://sites.google.com/site/peraperaprv/Home&quot; rel=&quot;nofollow&quot;&gt;P3:PeraPeraPrv&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://mob-mc.com&quot; rel=&quot;nofollow&quot;&gt;\uff08\u4eee\u79f0\uff09\u30c4\u30a4\u30af\u30ea\u30c3\u30af twiclick&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twittbot.net/&quot; rel=&quot;nofollow&quot;&gt;twittbot.net&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://tabtter.jp&quot; rel=&quot;nofollow&quot;&gt;\u30bf\u30d6\u30c3\u30bf\u30fc&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://locolabo.com/mz/&quot; rel=&quot;nofollow&quot;&gt;\u30ed\u30b3\u30e9\u30dc\u5bae\u5d0e\u770c&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.google.co.jp&quot; rel=&quot;nofollow&quot;&gt;himeko24&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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&quot;\u597d\u304d\u306b\u3084\u308c\u3070\u3044\u3044&quot;\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&quot;\u80cc\u8ca0\u3048&quot;\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":"&lt;a href=&quot;http://tweetlogix.com&quot; rel=&quot;nofollow&quot;&gt;Tweetlogix&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://mobile.twitter.com&quot; rel=&quot;nofollow&quot;&gt;Mobile Web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twittbot.net/&quot; rel=&quot;nofollow&quot;&gt;twittbot.net&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://janetter.net/&quot; rel=&quot;nofollow&quot;&gt;Janetter&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://d.hatena.ne.jp/fn7&quot; rel=&quot;nofollow&quot;&gt;\u65e5\u672c\u8a9e\u65e5\u672c\u8a9e\u7ffb\u8a33\u30b8\u30a7\u30cd\u30ec\u30fc\u30bf&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twittbot.net/&quot; rel=&quot;nofollow&quot;&gt;twittbot.net&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.flight.co.jp/iPhone/TweetMe/&quot; rel=&quot;nofollow&quot;&gt;TweetMe for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://sites.google.com/site/yorufukurou/&quot; rel=&quot;nofollow&quot;&gt;YoruFukurou&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://mobile.twitter.com&quot; rel=&quot;nofollow&quot;&gt;Twitter for Android&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.flight.co.jp/iPhone/TweetMe/&quot; rel=&quot;nofollow&quot;&gt;TweetMe for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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&lt;&lt;visa\u30ae\u30d5\u30c8\u30ab\u30fc\u30c910000\u5186\u5206\u3092\u6bce\u6708\u62bd\u9078\u3067\u30d7\u30ec\u30bc\u30f3\u30c8&gt;&gt; \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":"&lt;a href=&quot;http://twittbot.net/&quot; rel=&quot;nofollow&quot;&gt;twittbot.net&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twimi.jp/?r=via&quot; rel=&quot;nofollow&quot;&gt;twimi\u2606new&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twtr.jp&quot; rel=&quot;nofollow&quot;&gt;Keitai Web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.nibirutech.com&quot; rel=&quot;nofollow&quot;&gt;TwitBird&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twittbot.net/&quot; rel=&quot;nofollow&quot;&gt;twittbot.net&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://mob-mc.com&quot; rel=&quot;nofollow&quot;&gt;\uff08\u4eee\u79f0\uff09\u30c4\u30a4\u30af\u30ea\u30c3\u30af twiclick&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://sites.google.com/site/yorufukurou/&quot; rel=&quot;nofollow&quot;&gt;YoruFukurou&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twittbot.net/&quot; rel=&quot;nofollow&quot;&gt;twittbot.net&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twittbot.net/&quot; rel=&quot;nofollow&quot;&gt;twittbot.net&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www.echofon.com/&quot; rel=&quot;nofollow&quot;&gt;Echofon&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://janetter.net/&quot; rel=&quot;nofollow&quot;&gt;Janetter&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://www24.atpages.jp/aoi2/bot.php&quot; rel=&quot;nofollow&quot;&gt;\u5de1\u308b\u97f3&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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&quot;\u597d\u304d\u306b\u3084\u308c\u3070\u3044\u3044&quot;\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&quot;\u80cc\u8ca0\u3048&quot;\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":"&lt;a href=&quot;http://tweetlogix.com&quot; rel=&quot;nofollow&quot;&gt;Tweetlogix&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twicca.r246.jp/&quot; rel=&quot;nofollow&quot;&gt;twicca&lt;/a&gt;"},{"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":"&lt;a href=&quot;http://mixi.jp/promotion.pl?id=voice_twitter&quot; rel=&quot;nofollow&quot;&gt; mixi \u30dc\u30a4\u30b9 &lt;/a&gt;"},{"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":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"}],"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"}
+ test/json-data/jp50.json view
@@ -0,0 +1,1 @@+{"results":[{"from_user_id_str":"2458313","profile_image_url":"http://a2.twimg.com/profile_images/1203653060/fure091226_normal.png","created_at":"Thu, 27 Jan 2011 20:30:04 +0000","from_user":"19princess","id_str":"30724239224995840","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6d77\u6674\u300c\u672c\u65e5\u306e\u6771\u4eac\u306e\u304a\u5929\u6c17\u306f\u6674\u6642\u3005\u66c7\u3067\u3057\u3087\u3046\u3002\u6700\u9ad8\u6c17\u6e29\u306f8\u5ea6\u3001\u6700\u4f4e\u6c17\u6e29\u306f1\u5ea6\u3067\u3059\u3002\u3042\u306a\u305f\u306e\u4eca\u65e5\u306e\u4eba\u751f\u306b\u3068\u3073\u3063\u304d\u308a\u306e\u304a\u5929\u6c17\u3092\u2665\u300d","id":30724239224995840,"from_user_id":2458313,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://babyprincess.sakura.ne.jp/about/&quot; rel=&quot;nofollow&quot;&gt;\u5929\u4f7f\u5bb6\u306e\u88cf\u5c71&lt;/a&gt;"},{"from_user_id_str":"66578965","profile_image_url":"http://a0.twimg.com/profile_images/1183763267/fossetta_normal.png","created_at":"Thu, 27 Jan 2011 20:00:04 +0000","from_user":"Fossetta_Tokyo","id_str":"30716689779785729","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u304a\u306f\u3088\u3046\u3054\u3056\u3044\u307e\u3059!!\u6771\u4eac\u90fd\u3001\u672c\u65e5\u306e\u304a\u5929\u6c17\u306f\u6674\u6642\u3005\u66c7\u3002\u6700\u9ad8\u6c17\u6e298\u5ea6\u3001\u6700\u4f4e\u6c17\u6e291\u5ea6\u3002\u6771\u4eac\u5730\u65b9\u3067\u306f\u3001\u7a7a\u6c17\u306e\u4e7e\u71e5\u3057\u305f\u72b6\u614b\u304c\u7d9a\u3044\u3066\u3044\u307e\u3059\u3002\u706b\u306e\u53d6\u308a\u6271\u3044\u306b\u6ce8\u610f\u3057\u3066\u4e0b\u3055\u3044\u3002\u4f0a\u8c46\u8af8\u5cf6\u3068\u5c0f\u7b20\u539f\u8af8\u5cf6\u306b\u306f\u3001\u5f37\u98a8\u3001\u6ce2\u6d6a\u3001\u4e7e\u71e5\u3001\u971c\u306e\u6ce8\u610f\u5831\u3092\u767a\u8868\u4e2d\u3067\u3059\u3002","id":30716689779785729,"from_user_id":66578965,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://bit.ly/Fossetta&quot; rel=&quot;nofollow&quot;&gt;\u30d5\u30a9\u30bb\u30c3\u30bf ver.3.1.1&lt;/a&gt;"},{"from_user_id_str":"104041146","profile_image_url":"http://a2.twimg.com/profile_images/863965118/001jwatokyo_normal.jpg","created_at":"Thu, 27 Jan 2011 19:44:33 +0000","from_user":"jwa_tokyo","id_str":"30712787537756160","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6c17\u8c61\u5e81\u304b\u3089\u6771\u4eac\u306e\u5929\u6c17\u4e88\u5831\u304c\u767a\u8868\u3055\u308c\u307e\u3057\u305f\u3000\u305d\u306e\u5929\u6c17\u4e88\u5831\u3092\u3053\u3053\u3067\u3064\u3076\u3084\u3053\u3046\u304b\u306a\u3041\uff5e\uff1f\u3000\u8003\u3048\u4e2d\u3000\u307e\u3066\u6b21\u53f7\uff08\u7b11","id":30712787537756160,"from_user_id":104041146,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.docodemo.jp/twil/&quot; rel=&quot;nofollow&quot;&gt;Twil2 (Tweet Anytime, Anywhere by Mail)&lt;/a&gt;"},{"from_user_id_str":"144500192","profile_image_url":"http://a3.twimg.com/a/1294874399/images/default_profile_3_normal.png","created_at":"Thu, 27 Jan 2011 18:59:33 +0000","from_user":"kyo4to4","id_str":"30701462774358016","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u90fd \u516b\u4e08\u5cf6 - \u4eca\u65e5\u306e\u5929\u6c17\u306f\u30fb\u30fb\u30fb\u66c7\u306e\u3061\u6674\u3067\u3059\u306e\uff01","id":30701462774358016,"from_user_id":144500192,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/kyo4to4&quot; rel=&quot;nofollow&quot;&gt;lost-sheep-bot&lt;/a&gt;"},{"from_user_id_str":"165724582","profile_image_url":"http://a0.twimg.com/profile_images/1222842347/163087_1256281064506_1753997852_484926_2761052_n_normal.jpg","created_at":"Thu, 27 Jan 2011 17:39:06 +0000","from_user":"Rifqi_19931020","id_str":"30681213748387840","metadata":{"result_type":"recent"},"to_user_id":113796067,"text":"@CHLionRagbaby \u30b1\u30f3\u3061\u3083\u3093\u3001\u671d\u4eca\u307e\u3067\u306e\u81ea\u5206\u306e\u30db\u30fc\u30e0\u30a8\u30ea\u30a2\u304b\u3089\u307e\u3060\u975e\u5e38\u306b\u5bd2\u3044\u3068\u96e8\u304c\u964d\u3063\u3066\u3044\u305f..\u3069\u306e\u3088\u3046\u306b\u73fe\u5728\u306e\u6771\u4eac\u306e\u5929\u6c17\uff1f","id":30681213748387840,"from_user_id":165724582,"to_user":"CHLionRagbaby","geo":null,"iso_language_code":"ja","to_user_id_str":"113796067","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"120911929","profile_image_url":"http://a0.twimg.com/profile_images/772435076/20100312___capture2_normal.png","created_at":"Thu, 27 Jan 2011 17:28:30 +0000","from_user":"Cirno_fan","id_str":"30678546020040705","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4eca\u65e5\u306e\u6771\u4eac\u306e\u5929\u6c17\u306f\u3001\u66c7\u6642\u3005\u6674\u3067\u6700\u9ad8\u6c17\u6e29\u306f8\u2103\uff01 \u6700\u4f4e\u6c17\u6e29\u306f2\u2103\u3060\u3063\u305f\u3088\uff01 RT @mimi22999 \uff08\uff65\u2200\uff65\uff09\uff4c\u3001\u865a\u5f31\u306a\u8005\u306b\u3068\u3063\u3066\u3001\u6717\u3089\u304b\u306a\u9854\u306f\u4e0a\u5929\u6c17\u3068\u540c\u3058\u304f\u3089\u3044\u3046\u308c\u3057\u3044\u3082\u306e\u3060\u3002\u30d5\u30e9\u30f3\u30af\u30ea\u30f3 #tenki #bot","id":30678546020040705,"from_user_id":120911929,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://blog.livedoor.jp/fairycirno/archives/34686.html&quot; rel=&quot;nofollow&quot;&gt;\u5e7b\u60f3\u90f7 \u9727\u306e\u6e56&lt;/a&gt;"},{"from_user_id_str":"65976527","profile_image_url":"http://a0.twimg.com/profile_images/452810990/little_italies_____normal.jpg","created_at":"Thu, 27 Jan 2011 17:00:03 +0000","from_user":"heta_weather01","id_str":"30671388754845696","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3010\u30d8\u30bf\u5929\u3011Tere hommikust.\u30a8\u30b9\u30c8\u30cb\u30a2\u3067\u3059\u3002\u4eca\u65e5\u306e\u6771\u4eac\u306e\u5929\u6c17\u306f\u6674\u6642\u3005\u66c7\u3067\u660e\u65e5\u306f\u66c7\u308a\u3067\u3059\u3002\u3061\u306a\u307f\u306b\u50d5\u306e\u3068\u3053\u308d\u3067\u306f\u66c7\u308a\u3067\u6c17\u6e29-7\u2103\u3067\u3059\u3002\u3061\u306a\u307f\u306b\u30b9\u30ab\u30a4\u30d7\u306e\u958b\u767a\u672c\u90e8\u306f\u50d5\u306e\u5bb6\u306b\u3042\u308b\u3093\u3067\u3059\u3002","id":30671388754845696,"from_user_id":65976527,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www15.atpages.jp/~kageyanma/&quot; rel=&quot;nofollow&quot;&gt;\u5730\u7403\u306e\u4e2d&lt;/a&gt;"},{"from_user_id_str":"7278433","profile_image_url":"http://a3.twimg.com/profile_images/1218965303/michael-1_normal.png","created_at":"Thu, 27 Jan 2011 16:50:16 +0000","from_user":"shimohiko","id_str":"30668926035689472","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3042\u308a\u3002\n\u3010\u7f8e\u4eba\u5929\u6c17/\u6771\u4eac\u3011\u7f8e\u4eba\u5929\u6c17\u30ad\u30e3\u30b9\u30bf\u30fc\u306e&quot;\u3055\u3042\u3084\u3093\u3055\u3093&quot;\u306b\u3088\u308b\u3068\u300c1/29(\u571f)\u306f\u304f\u3082\u308a\u3067\u3001\u964d\u6c34\u78ba\u738740%\u3001\u6700\u9ad8\u6c17\u6e29\u306f6\u2103\u3067\u6700\u4f4e\u6c17\u6e29\u306f1\u2103\u3067\u3059\u300d\u7f8e\u4eba\u5929\u6c17\u21d2http://bit.ly/djB8th http://twitpic.com/3twnl0 #bt_tenki","id":30668926035689472,"from_user_id":7278433,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://bijintenki.jp&quot; rel=&quot;nofollow&quot;&gt;bijintenki.jp&lt;/a&gt;"},{"from_user_id_str":"61770","profile_image_url":"http://a3.twimg.com/profile_images/1206955079/tw172a_normal.png","created_at":"Thu, 27 Jan 2011 16:40:52 +0000","from_user":"rsky","id_str":"30666561853333504","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3075\u3068\u591c\u7a7a\u3092\u898b\u4e0a\u3052\u3066\u30aa\u30ea\u30aa\u30f3\u304c\u898b\u3048\u306a\u304f\u3066\u300c\u6771\u4eac\u306b\u306f\u7a7a\u304c\u306a\u3044\u300d\u3068\u667a\u6075\u5b50\u306e\u3088\u3046\u306a\u3053\u3068\u3092\u601d\u3063\u305f\u308f\u3051\u3060\u304c\u3001\u305f\u3076\u3093\u534a\u5206\u3050\u3089\u3044\u306f\u5929\u6c17\u306e\u305b\u3044\u3067\u3059","id":30666561853333504,"from_user_id":61770,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"103259265","profile_image_url":"http://a0.twimg.com/profile_images/767857973/anime_icon_normal.gif","created_at":"Thu, 27 Jan 2011 16:37:42 +0000","from_user":"liveshowonly","id_str":"30665765698928640","metadata":{"result_type":"recent"},"to_user_id":null,"text":"iPhone\u5929\u6c17\u3002\u6771\u4eac4\u2103\u3063\u3066\u7d50\u69cb\u5bd2\u304f\u306a\u3044\u3058\u3083\u3093\u3002\uff08\u78ba\u304b\u306b\u3082\u306e\u51c4\u304f\u5bd2\u3044\u8a33\u3067\u306f\u7121\u3044\uff09\u3002\u798f\u5ca1\u5e02\u306f1\u2103\u3060\u3002\u52dd\u3061\u3060\u305c\u3002Rock'n'roll","id":30665765698928640,"from_user_id":103259265,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"165242761","profile_image_url":"http://a1.twimg.com/profile_images/1147334744/SN3E00600001_normal.jpg","created_at":"Thu, 27 Jan 2011 16:37:35 +0000","from_user":"deuxavril0502","id_str":"30665736556912640","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6b8b\u5ff5\u3001\u79c1\u306f\u6c96\u7e04\u3067\u3059(&gt;_&lt;)\u3067\u3082\u304a\u5929\u6c17\u826f\u3055\u305d\u3046\u3067\u826f\u304b\u3063\u305f\u306d\u3002\u3053\u3061\u3089\u306f\u96e8\u3088\uff5eRT @rinandy2010: \u305d\u3046\u3067\u3059\u3063\u266a\u51fa\u5f35\u3067(^^)\u304a\u306d\u3048\u3055\u307e\u306f\u6771\u4eac\u3067\u3059\u304b\uff1f\u3081\u3063\u3061\u3083\u5929\u6c17\u826f\u304f\u3066\u3073\u3063\u304f\u308a\u3067\u3059\u3002\u624b\u888b\u3068\u304b\u5168\u7136\u3044\u3089\u306a\u3044\u3067\u3059\u306d\u30fc RT @deuxavril0502 \u6771\u4eac\u306a\u306e\u30fc\uff1f","id":30665736556912640,"from_user_id":165242761,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.echofon.com/&quot; rel=&quot;nofollow&quot;&gt;Echofon&lt;/a&gt;"},{"from_user_id_str":"163900288","profile_image_url":"http://a1.twimg.com/profile_images/1210224823/icon12945064955238_normal.jpg","created_at":"Thu, 27 Jan 2011 16:24:37 +0000","from_user":"nyao_yurichan","id_str":"30662472734089216","metadata":{"result_type":"recent"},"to_user_id":100985873,"text":"@ray_ko302 \u767a\u898b\u3042\u308a\u304c\u3068\u3067\u3059\u3045\u3002\u3053\u3061\u3089\u3067\u3082\u3088\u308d\u3057\u304f\u306d\u3002\u6771\u4eac\u306f\u4eca\u65e5\u3082\u4e7e\u71e5\u3067\u5927\u5909\u3088\u3002\u305d\u3063\u3061\u3068\u771f\u9006\u306e\u5929\u6c17\u3060\u306d\u3002\u30a2\u30a4\u30b9\u30d0\u30fc\u30f3\u304d\u3092\u3064\u3051\u3066\u3088\u306d\u3002","id":30662472734089216,"from_user_id":163900288,"to_user":"ray_ko302","geo":null,"iso_language_code":"ja","to_user_id_str":"100985873","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"49227098","profile_image_url":"http://a3.twimg.com/profile_images/965007882/____normal.jpg","created_at":"Thu, 27 Jan 2011 15:52:26 +0000","from_user":"dosannko6","id_str":"30654371016478720","metadata":{"result_type":"recent"},"to_user_id":108570870,"text":"@peke_hajiP \u4ffa\u304c\u6771\u4eac \u6765\u3066\u6700\u521d\u306b\u9a5a\u3044\u305f\u306e\u304c\u3001\u5929\u6c17\u4e88\u5831\u3067\u82b1\u7c89\u60c5\u5831\u304c\u6d41\u308c\u308b\u3053\u3068\u3067\u3001\u6700\u521d\u306b\u8a66\u3057\u305f\u306e\u304c \u30b4\u30ad\u69d8 \u53ec\u559a\u306e\u5100\u5f0f\u3067\u3059\u304a\uff1f","id":30654371016478720,"from_user_id":49227098,"to_user":"peke_hajip","geo":null,"iso_language_code":"ja","to_user_id_str":"108570870","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"71148934","profile_image_url":"http://a0.twimg.com/profile_images/1209223630/image_normal.jpg","created_at":"Thu, 27 Jan 2011 15:46:49 +0000","from_user":"123keiko","id_str":"30652958311981058","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u9727\u5cf6\u306e\u964d\u7070\u306e\u30cb\u30e5\u30fc\u30b9\u3092\u898b\u3066\u601d\u3044\u51fa\u3057\u307e\u3057\u305f\u3002\u4e0a\u4eac\u3057\u305f\u59cb\u3081\u306e\u9803\u3001\u6771\u4eac\u306f1\u5e74\u4e2d\u3001\u7070\u304c\u964d\u3089\u306a\u3044\u304b\u3089\u7a7a\u6c17\u304c\u6f84\u3093\u3067\u3066\u904e\u3054\u3057\u3084\u3059\u3044\u306a\u3041\u3001\u3068\u601d\u3063\u305f\u306a\u3041\u3001\u3063\u3066\u3002\n\u5b9f\u5bb6\u306f\u51ac\u306e\u5b63\u7bc0\u98a8\u3067\u685c\u5cf6\u306e\u7070\u304c\u964d\u308b\u5730\u533a\u3067\u3057\u305f\u3002\u9e7f\u5150\u5cf6\u306e\u5929\u6c17\u4e88\u5831\u3067\u306f\u3001\u6bce\u65e5\u3001\u685c\u5cf6\u4e0a\u7a7a\u306e\u98a8\u5411\u304d\u4e88\u5831\u304c\u3067\u307e\u3059\u3002\u3053\u308c\u304b\u3089\u306f\u9727\u5cf6\u3082\u304b\u306a\uff1f","id":30652958311981058,"from_user_id":71148934,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"91124773","profile_image_url":"http://a3.twimg.com/profile_images/1139308356/prof101007_3-1_normal.jpg","created_at":"Thu, 27 Jan 2011 15:43:35 +0000","from_user":"sanposuruhito","id_str":"30652146277945345","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4eca\u5bb5\u306e\u90fd\u5fc3\u306f\u3001\u8eab\u3082\u5f15\u304d\u7de0\u307e\u308b\u3068\u3044\u3046\u3088\u308a\u306f\u51cd\u3048\u308b\u7a0b\u306e\u51b7\u6c17\u3092\u611f\u3058\u308b\u5bd2\u3044\u591c\u3067\u3059\u3002\u660e\u65e5\u65e5\u4e2d\u306e\u6771\u4eac\u306e\u5929\u6c17\u306f\u3001\u5915\u65b9\u306b\u591a\u5c11\u96f2\u304c\u51fa\u308b\u5834\u6240\u304c\u3042\u308a\u305d\u3046\u306a\u3082\u306e\u306e\u6982\u306d\u6674\u308c\u7a7a\u304c\u5e83\u304c\u308a\u7d9a\u3051\u305d\u3046\u3067\u3059\u3002\u6700\u9ad8\u6c17\u6e29\u306f\u30015-6\u5ea6\u4f4d\u3068\u306a\u308a\u305d\u3046\u3067\u3059\u3002#weather_tokyo","id":30652146277945345,"from_user_id":91124773,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://projects.playwell.jp/go/Saezuri&quot; rel=&quot;nofollow&quot;&gt;Saezuri&lt;/a&gt;"},{"from_user_id_str":"104712480","profile_image_url":"http://a3.twimg.com/profile_images/1204016928/icon5087697006727791368kuro2_normal.jpg","created_at":"Thu, 27 Jan 2011 15:31:51 +0000","from_user":"asongfor_xx","id_str":"30649192296751104","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u7f8e\u4eba\u5929\u6c17\u304b\u3089tweet\u3059\u308b\u3068\u3053\u3093\u306a\u611f\u3058\u306a\u3093\u3060\u306a\u3002 RT asongfor_xx: \u3010\u7f8e\u4eba\u5929\u6c17/\u6771\u4eac\u3011\u7f8e\u4eba\u5929\u6c17\u30ad\u30e3\u30b9\u30bf\u30fc\u306e&quot;\u304b\u306a\u3053\u3055\u3093&quot;\u306b\u3088\u308b\u3068\u300c1/28(\u91d1)\u306f\u6674\u6642\u3005\u304f\u3082\u308a\u3067\u3001\u964d\u6c34\u78ba\u73870%\u3001\u6700\u9ad8\u6c17\u6e29\u306f8\u2103\u3067\u6700\u4f4e\u6c17\u6e29\u306f1\u2103\u3067\u3059\u300d\u7f8e\u4eba\u5929\u6c17\u21d2http://bit.ly/djB8th","id":30649192296751104,"from_user_id":104712480,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twipple.jp/&quot; rel=&quot;nofollow&quot;&gt;\u3064\u3044\u3063\u3077\u308b for iPhone&lt;/a&gt;"},{"from_user_id_str":"165965113","profile_image_url":"http://a0.twimg.com/profile_images/1200885316/shogomeguro_normal.jpg","created_at":"Thu, 27 Jan 2011 15:24:35 +0000","from_user":"shogomeguro","id_str":"30647362477105152","metadata":{"result_type":"recent"},"to_user_id":null,"text":"2011.1.26 \u793e\u7a93\u304b\u3089\u3002\u4e0d\u601d\u8b70\u306a\u5929\u6c17\u3067\u3053\u306e\u5f8c\u96ea\u304c\u3061\u3089\u3064\u3044\u305f\u3093\u3060\u3088\u306d\u3002\u6771\u4eac\u306e\u521d\u96ea\u3067\u3057\u305f\u3002 http://instagr.am/p/BO_xn/","id":30647362477105152,"from_user_id":165965113,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://instagr.am&quot; rel=&quot;nofollow&quot;&gt;instagram&lt;/a&gt;"},{"from_user_id_str":"166018520","profile_image_url":"http://a0.twimg.com/profile_images/1207460953/100-40030_normal.jpg","created_at":"Thu, 27 Jan 2011 15:18:17 +0000","from_user":"115nayume","id_str":"30645776254238722","metadata":{"result_type":"recent"},"to_user_id":118384679,"text":"@dancinpea09 \u6771\u4eac\u3001\u660e\u65e5\u3082\u5929\u6c17\u826f\u3044\u307f\u305f\u3044\u3067\u3001\u3088\u304b\u3063\u305f\u3067\u3059\u306d\u30fc\u266a  \u30ca\u30a4\u30b9\u30c8\u30ea\u30c3\u30d7\uff01\u304a\u3084\u3059\u307f\u306a\u3055\u3044\u3002 http://twitpic.com/3tvun3","id":30645776254238722,"from_user_id":166018520,"to_user":"dancinpea09","geo":null,"iso_language_code":"ja","to_user_id_str":"118384679","source":"&lt;a href=&quot;http://tweetli.st/&quot; rel=&quot;nofollow&quot;&gt;TweetList!&lt;/a&gt;"},{"from_user_id_str":"202937674","profile_image_url":"http://a1.twimg.com/profile_images/1218797578/______2_normal.jpg","created_at":"Thu, 27 Jan 2011 15:11:48 +0000","from_user":"ryuusisan","id_str":"30644146498699264","metadata":{"result_type":"recent"},"to_user_id":203058384,"text":"@manaasutakshi \u6771\u4eac\u306f\u964d\u3063\u3066\u306a\u3044\u3093\u3067\u3059\u304b\u30fb\u30fb\u30fb\u5929\u6c17\u4e88\u5831\u306b\u3088\u308b\u3068\u660e\u65e5\u3082\u6771\u4eac\u306f\u964d\u3089\u306a\u3044\u305d\u3046\u3067\u3059\u306d\uff01\uff01\u79c1\u306e\u4f4f\u3093\u3067\u3044\u308b\u3068\u3053\u308d\u306f\u5fae\u5999\u306b\u964d\u308a\u305d\u3046\u3067\u51fa\u52e4\u6642\u306b\u964d\u3063\u3066\u305f\u3089\u3061\u3087\u3063\u3068\u5acc\u3060\u306a\u3041\u3000\u306a\u3093\u3066\u601d\u3044\u307e\u3059","id":30644146498699264,"from_user_id":202937674,"to_user":"manaasutakshi","geo":null,"iso_language_code":"ja","to_user_id_str":"203058384","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"3222182","profile_image_url":"http://a0.twimg.com/profile_images/1199090957/ProfilePhoto_normal.png","created_at":"Thu, 27 Jan 2011 15:09:35 +0000","from_user":"44mune","id_str":"30643589545459713","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3010\u7f8e\u4eba\u5929\u6c17/\u6771\u4eac\u3011\u7f8e\u4eba\u5929\u6c17\u30ad\u30e3\u30b9\u30bf\u30fc\u306e&quot;\u306e\u308a\u3055\u3093&quot;\u306b\u3088\u308b\u3068\u300c1/28(\u91d1)\u306f\u304f\u3082\u308a\u306e\u3061\u6674\u3067\u3001\u964d\u6c34\u78ba\u738710%\u3001\u6700\u9ad8\u6c17\u6e29\u306f9\u2103\u3067\u6700\u4f4e\u6c17\u6e29\u306f2\u2103\u3067\u3059\u300d http://twitpic.com/3tvruh","id":30643589545459713,"from_user_id":3222182,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://bijintenki.jp&quot; rel=&quot;nofollow&quot;&gt;bijintenki.jp&lt;/a&gt;"},{"from_user_id_str":"154341982","profile_image_url":"http://a0.twimg.com/profile_images/1155496864/_____normal.jpg","created_at":"Thu, 27 Jan 2011 15:02:39 +0000","from_user":"slave_420_bot","id_str":"30641845490946049","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4eca\u30f3\u3068\u3053\u899a\u3048\u3066\u308b\u306e\u306f\u300c\u672d\u5e4c\u300d\u300c\u4ed9\u53f0\u300d\u300c\u6771\u4eac\u300d\u300c\u5927\u962a\u300d\u300c\u540d\u53e4\u5c4b\u300d\u300c\u798f\u5ca1\u300d\u306e\u4eca\u65e5\u3068\u660e\u65e5\u306e\u5929\u6c17\u3060\u306a\u3002\u5929\u6c17\u304c\u77e5\u308a\u305f\u3044\u6642\u306f\u300c\u5834\u6240\u300d\u3068\u300c\u4eca\u65e5\u306e\u5929\u6c17\u300d\u304b\u300c\u660e\u65e5\u306e\u5929\u6c17\u300d\u3092\u304a\u7533\u3057\u4ed8\u3051\u304f\u3060\u3055\u3044\u3001\u304a\u5b22\u69d8\uff1f","id":30641845490946049,"from_user_id":154341982,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://bot.syoyu.net/&quot; rel=&quot;nofollow&quot;&gt;\u7adc\u30f6\u5cf0\u90b8\u306e\u3069\u3053\u304b&lt;/a&gt;"},{"from_user_id_str":"72042678","profile_image_url":"http://a3.twimg.com/profile_images/1198771027/larxene_normal.jpg","created_at":"Thu, 27 Jan 2011 15:01:57 +0000","from_user":"larxene_bot","id_str":"30641668772339712","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4eca\u65e5\u306e\u5929\u6c17\u306f \u672d\u5e4c\u304c\u6674\u308c \u4ed9\u53f0\u304c\u66c7\u6642\u3005\u96ea \u6771\u4eac\u304c\u6674\u306e\u3061\u66c7 \u540d\u53e4\u5c4b\u304c\u6674\u6642\u3005\u66c7 \u5927\u962a\u304c\u6674\u6642\u3005\u66c7 \u798f\u5ca1\u304c\u6674\u308c \u3089\u3057\u3044\u308f\u3088 \u6ce8\u610f\u3057\u306a\u3055\u3044","id":30641668772339712,"from_user_id":72042678,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www4.kiwi-us.com/~yuuna/larxene_bot_manual/index.html&quot; rel=&quot;nofollow&quot;&gt;\u5fd8\u5374\u306e\u57ce \u5730\u4e0a\u306e12\u968e&lt;/a&gt;"},{"from_user_id_str":"101331893","profile_image_url":"http://a1.twimg.com/sticky/default_profile_images/default_profile_0_normal.png","created_at":"Thu, 27 Jan 2011 15:01:34 +0000","from_user":"yoshiftan","id_str":"30641572240424961","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u306e\u5929\u6c17\u4e88\u5831\u3092\u898b\u3066\u3073\u3063\u304f\u308a\uff01\u6691\u305d\u3046\u3060\u306a\u3053\u308a\u3083\u3002","id":30641572240424961,"from_user_id":101331893,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"Keitai Mail"},{"from_user_id_str":"65207550","profile_image_url":"http://a3.twimg.com/profile_images/448731969/_________R_normal.jpg","created_at":"Thu, 27 Jan 2011 15:01:33 +0000","from_user":"kabuyo","id_str":"30641566469066752","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u5929\u6c17\u4e88\u5831\u3067\u306f\u6771\u4eac\u3067\u306f\u4e7e\u71e5\u6ce8\u610f\u5831\u304c\u7d9a\u3044\u3066\u3044\u308b\u3089\u3057\u3044\u306e\u306b\u3001\u306a\u305c\u79c1\u304c\u5e72\u3057\u305f\u6d17\u6fef\u7269\u306f\u96e8\u306b\u6fe1\u308c\u3066\u3057\u307e\u3063\u305f\u306e\u3060\u308d\u3046\u304b\u2025\u3000\u3088\u3063\u307d\u3069\u904b\u304c\u60aa\u3044\u3089\u3057\u3044\u2025","id":30641566469066752,"from_user_id":65207550,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"80309352","profile_image_url":"http://a1.twimg.com/profile_images/1223620418/image_normal.jpg","created_at":"Thu, 27 Jan 2011 14:54:30 +0000","from_user":"mikutyan","id_str":"30639792026812416","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u306e\u660e\u65e5\u306e\u5929\u6c17\u6559\u3048\u3066","id":30639792026812416,"from_user_id":80309352,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"80309352","profile_image_url":"http://a1.twimg.com/profile_images/1223620418/image_normal.jpg","created_at":"Thu, 27 Jan 2011 14:53:06 +0000","from_user":"mikutyan","id_str":"30639439847890944","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u660e\u65e5\u306e\u6771\u4eac\u306e\u5929\u6c17\u306a\u3093\u3060\u308d\u3046 \u96e8\u964d\u3063\u305f\u3089\u56f0\u308b\u3002","id":30639439847890944,"from_user_id":80309352,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"120911929","profile_image_url":"http://a0.twimg.com/profile_images/772435076/20100312___capture2_normal.png","created_at":"Thu, 27 Jan 2011 14:47:19 +0000","from_user":"Cirno_fan","id_str":"30637984684449792","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3042\u305f\u3044\u30c1\u30eb\u30ce\uff01\u30dc\u30c3\u30c8\u3060\u3051\u3069\u5929\u6c17\u4e88\u5831\u3082\u3067\u304d\u308b\u3088\uff01\u300c\u6771\u4eac\u306e\u4eca\u65e5\u306e\u5929\u6c17\u6559\u3048\u3066\u300d\u307f\u305f\u3044\u306bTL\u767a\u8a00\u3057\u3066\u304f\u308c\u308c\u3070\u8abf\u3079\u3066\u3042\u3052\u308b\uff01 #followme #followmejp #followmevip #tenki","id":30637984684449792,"from_user_id":120911929,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://blog.livedoor.jp/fairycirno/archives/34686.html&quot; rel=&quot;nofollow&quot;&gt;\u5e7b\u60f3\u90f7 \u9727\u306e\u6e56&lt;/a&gt;"},{"from_user_id_str":"33858777","profile_image_url":"http://a0.twimg.com/profile_images/352864695/muga_normal.jpg","created_at":"Thu, 27 Jan 2011 14:46:12 +0000","from_user":"collonist","id_str":"30637702105796610","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u3063\u3066\u51ac\u306f\u57fa\u672c\u7684\u306b\u6674\u308c\u3066\u308b\u304b\u3089\u3001\u5929\u6c17\u4e88\u5831\u898b\u306a\u304f\u3066\u3082\u5168\u7136\u554f\u984c\u306a\u3044\u3002\u5c71\u5f62\u3060\u3068\u660e\u65e5\u306f\u3069\u3093\u3060\u3051\u96ea\u304c\u964d\u308b\u306e\u304b\u3001\u3069\u3093\u3060\u3051\u5bd2\u3044\u306e\u304b\u628a\u63e1\u3057\u3066\u3068\u304d\u305f\u3044\u306e\u3067\u3001\u5929\u6c17\u4e88\u5831\u306f\u5fc5\u305a\u30c1\u30a7\u30c3\u30af\u3057\u3066\u305f\u306e\u3060\u304c\u3002","id":30637702105796610,"from_user_id":33858777,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"79336228","profile_image_url":"http://a0.twimg.com/profile_images/1130029876/zmanmu_normal.png","created_at":"Thu, 27 Jan 2011 14:30:23 +0000","from_user":"atsuki777","id_str":"30633725041573890","metadata":{"result_type":"recent"},"to_user_id":null,"text":"MXTV\u306e\u5929\u6c17\u4e88\u5831\u521d\u3081\u3066\u898b\u305f\u3051\u3069\u6771\u4eac\u753a\u7530\u516b\u738b\u5b50\u3063\u3066\u5730\u57df\u8868\u793a\u304c\u2026w\u516b\u738b\u5b50\u3068\u753a\u7530\u306f\u6771\u4eac\u3058\u3083\u306a\u3044\u306e\u304bwww","id":30633725041573890,"from_user_id":79336228,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.echofon.com/&quot; rel=&quot;nofollow&quot;&gt;Echofon&lt;/a&gt;"},{"from_user_id_str":"90576097","profile_image_url":"http://a0.twimg.com/profile_images/1203320254/nanami1_normal.png","created_at":"Thu, 27 Jan 2011 14:28:26 +0000","from_user":"dycroft","id_str":"30633234245099521","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u306e\u660e\u65e5\u306e\u304a\u5929\u6c17\u3067\u3059","id":30633234245099521,"from_user_id":90576097,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"from_user_id_str":"147215268","profile_image_url":"http://a2.twimg.com/profile_images/1198555202/ichika-7.4.0-3P_normal.gif","created_at":"Thu, 27 Jan 2011 14:28:23 +0000","from_user":"kiaran5032","id_str":"30633222211637248","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u306e\u660e\u65e5\u306e\u304a\u5929\u6c17\u3067\u3059\u3002\u6674\u308c\u6642\u3005\u304f\u3082\u308a #MX","id":30633222211637248,"from_user_id":147215268,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"from_user_id_str":"1741599","profile_image_url":"http://a0.twimg.com/profile_images/1205744888/950637_normal.jpg","created_at":"Thu, 27 Jan 2011 14:28:21 +0000","from_user":"dasaitama","id_str":"30633212535382016","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u306e\u3001\u660e\u65e5\u306e\u304a\u5929\u6c17\u3067\u3059","id":30633212535382016,"from_user_id":1741599,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"from_user_id_str":"34140879","profile_image_url":"http://a3.twimg.com/profile_images/1186413535/__6_normal.jpg","created_at":"Thu, 27 Jan 2011 14:28:17 +0000","from_user":"ryuji_chaos","id_str":"30633197016449024","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u306e\u660e\u65e5\u306e\u304a\u5929\u6c17\u3067\u3059\u3002","id":30633197016449024,"from_user_id":34140879,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"1400","profile_image_url":"http://a0.twimg.com/profile_images/1198556839/westerndog_20090104_320x320_normal.jpg","created_at":"Thu, 27 Jan 2011 14:28:16 +0000","from_user":"westerndog","id_str":"30633191232503808","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u306e\u660e\u65e5\u306e\u304a\u5929\u6c17\u3067\u3059","id":30633191232503808,"from_user_id":1400,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"from_user_id_str":"89239832","profile_image_url":"http://a3.twimg.com/profile_images/519522846/noriko_normal.jpg","created_at":"Thu, 27 Jan 2011 14:15:01 +0000","from_user":"Noriko_Fujimoto","id_str":"30629857234788352","metadata":{"result_type":"recent"},"to_user_id":115645219,"text":"@nossa430402 \u5bcc\u5c71\u306f\u3059\u3054\u3044\u96ea\u307f\u305f\u3044\u3067\u3059\u306d\uff5e\uff08\u5bd2\u3063\uff09\u3000\u6771\u4eac\u306f\u305d\u306e\u5206\u6bce\u65e5\u826f\u3044\u5929\u6c17\u3067\u3059\u3002\u5bd2\u3044\u3051\u3069\u30fb\u30fb\u30fb\u3002","id":30629857234788352,"from_user_id":89239832,"to_user":"nossa430402","geo":null,"iso_language_code":"ja","to_user_id_str":"115645219","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"107265539","profile_image_url":"http://a0.twimg.com/sticky/default_profile_images/default_profile_3_normal.png","created_at":"Thu, 27 Jan 2011 14:01:10 +0000","from_user":"kurumasuki330","id_str":"30626371826884608","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u4eca\u9031\u571f\u66dc\u65e5\u3001\u8eca\u3067\u6771\u4eac\u304b\u3089\u6771\u540d\u3001\u7c73\u539f\u7d4c\u7531\u3067\u91d1\u6ca2\u306e\u5b9f\u5bb6\u3078\u3002\u305d\u3057\u3066\u3001\u6708\u66dc\u65e5\u306b\u6771\u4eac\u3078\u5e30\u308b\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u3002\u5929\u6c17\u4e88\u5831\u3060\u3068\u4eca\u9031\u672b\u3001\u5317\u9678\u5730\u65b9\u306f\u5927\u96ea\uff01\u5e30\u308c\u308b\u304b\u81ea\u4fe1\u304c\u306a\u304f\u306a\u3063\u3066\u304d\u305f\u3002\u307e\u305f\u3001\u305d\u306e\u6642\u5b9f\u6cc1\u4e2d\u7d99\u3057\u307e\u3059\u3002","id":30626371826884608,"from_user_id":107265539,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twtr.jp&quot; rel=&quot;nofollow&quot;&gt;Keitai Web&lt;/a&gt;"},{"from_user_id_str":"155313166","profile_image_url":"http://a3.twimg.com/profile_images/1167554721/73931_1408370184003_1674923704_920888_5686998_n_normal.jpg","created_at":"Thu, 27 Jan 2011 14:00:50 +0000","from_user":"takuya_aoki","id_str":"30626287127105536","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u306f\u3081\u3063\u3061\u3083\u3044\u3044\u5929\u6c17\u3067\u904e\u3054\u3057\u3084\u3059\u3044\u3051\u3069\u30c9\u30e9\u30a4\u30a2\u30a4\u306b\u306f\u3061\u3087\u3063\u3068\u304d\u3064\u3044\u306a\u30fb\u30fb\u30fb\u76ee\u85ac\u304c\u624b\u653e\u305b\u306a\u3044","id":30626287127105536,"from_user_id":155313166,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"179984398","profile_image_url":"http://a1.twimg.com/profile_images/1182382310/g4350_normal.jpg","created_at":"Thu, 27 Jan 2011 13:52:50 +0000","from_user":"aiilabo","id_str":"30624271902449664","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u30d6\u30ed\u30b0\u66f4\u65b0 \u25c6\u611f\u60c5\u3092\u307f\u3064\u3081\u308b\u65b9\u6cd5 - \u3053\u3053\u6570\u65e5\u3001\u6642\u6298\u96e8\u304c\u30d1\u30e9\u30d1\u30e9\u3000\u5fae\u5999\u306a\u5929\u6c17\u306e\u6771\u4eac\u304b\u3089\u3042\u308b\u304c\u307e\u307e\u3067\u3059\u3002 \n\n \u4eca\u65e5\u306f\u3001\u6628\u65e5\u306e\u300c\u30de\u30a4\u30ca\u30b9\u611f\u60c5\u306f\u60aa\u3067\u3059\u304b\uff1f\n.. \u27aa http://am6.jp/e3e9tS","id":30624271902449664,"from_user_id":179984398,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://feedtweet.am6.jp/&quot; rel=&quot;nofollow&quot;&gt;\u261e feedtweet.jp \u261c&lt;/a&gt;"},{"from_user_id_str":"185992391","profile_image_url":"http://a2.twimg.com/profile_images/1192695844/otenki_normal.png","created_at":"Thu, 27 Jan 2011 13:00:37 +0000","from_user":"otenki_luci_bot","id_str":"30611130938298368","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u767a\u58f2\u65e5\u304b\u2026\u2026\u541b\u305f\u3061\u306b\u3068\u3063\u3066\u306f\u591a\u5206\u300190\u65e5\u5f8c\u306e\u3053\u3068\u3060\u3002\u3055\u3066\u660e\u65e5\u306e\u6771\u4eac\u90fd\u306e\u5929\u6c17\u306f\u6674\u306e\u3061\u66c7\u3001\u6700\u9ad8\u6c17\u6e29\u306f8\u5ea6\u3060\u305d\u3046\u3060\u3002\u3055\u3059\u304c\u306b\u4f55\u304b\u7740\u305f\u65b9\u304c\u3044\u3044\u305e\u3001\u30a4\u30fc\u30ce\u30c3\u30af\u3002","id":30611130938298368,"from_user_id":185992391,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/otenki_luci_bot&quot; rel=&quot;nofollow&quot;&gt;\u304a\u3066\u3093\u304d\u308b\u3057\u3075\u3047\u308b&lt;/a&gt;"},{"from_user_id_str":"65976527","profile_image_url":"http://a0.twimg.com/profile_images/452810990/little_italies_____normal.jpg","created_at":"Thu, 27 Jan 2011 13:00:04 +0000","from_user":"heta_weather01","id_str":"30610995843964928","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3010\u30d8\u30bf\u5929\u3011Jo napot.\u30cf\u30f3\u30ac\u30ea\u30fc\u3067\u3059\u3002\u6771\u4eac\u306e\u5929\u6c17\u306f\u6674\u306e\u3061\u66c7\u3067\u660e\u65e5\u306f\u6674\u6642\u3005\u66c7\u3001\u79c1\u306e\u3068\u3053\u308d\u3067\u306f\u66c7\u308a\u3067-2\u2103\u3067\u3059\u3002\u3048\u3001\u3053\u306e\u30d5\u30e9\u30a4\u30d1\u30f3\u3067\u3059\u304b\uff1f\u2026\u3061\u3087\u3063\u3068\u500b\u4eba\u7684\u306b\u6bb4\u308a\u305f\u3044\u4eba\u304c\u3044\u308b\u3093\u3067\u3059\u266a","id":30610995843964928,"from_user_id":65976527,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www15.atpages.jp/~kageyanma/&quot; rel=&quot;nofollow&quot;&gt;\u5730\u7403\u306e\u4e2d&lt;/a&gt;"},{"from_user_id_str":"109740077","profile_image_url":"http://a0.twimg.com/profile_images/1212763349/1d3d3821-6b3a-449f-a636-05b95ce3d5d8_normal.png","created_at":"Thu, 27 Jan 2011 12:59:41 +0000","from_user":"snow_arai","id_str":"30610896141156354","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u6771\u4eac\u306f\u3001\u30ab\u30e9\u30ab\u30e9\u9023\u7d9a\u3000\uff13\u4f4d\u30bf\u30a4 - \u65e9\u8d77\u304d\u2606\u304a\u5929\u6c17\u2606ONAIR\u65e5\u8a18\uff1a\u65e5\u7d4c\u30a6\u30fc\u30de\u30f3\u30aa\u30f3\u30e9\u30a4\u30f3 http://j.mp/hxP3Di","id":30610896141156354,"from_user_id":109740077,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"53407951","profile_image_url":"http://a1.twimg.com/profile_images/397960795/airman_normal.jpg","created_at":"Thu, 27 Jan 2011 12:57:32 +0000","from_user":"Airman2009","id_str":"30610355541508096","metadata":{"result_type":"recent"},"to_user_id":null,"text":". @04mmy22 @qsk1 \u98a8\u3068\u96f2\u30fb\u30fb\u30fb\u98db\u884c\u6a5f\u306e\u5927\u5c0f\u554f\u308f\u305a\u3001\u3053\u308c\u3070\u304b\u308a\u306f\u3069\u3046\u3057\u3088\u3046\u3082\u7121\u3044\u3067\u3059\u3088\u306d\u3002 \u6700\u8fd1\u306e\u5357\u6771\u4eac\u306e\u5929\u6c17\u306f\u5909\u3067\u3059\u306d\u3002\u3002\u3002","id":30610355541508096,"from_user_id":53407951,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://sourceforge.jp/projects/tween/wiki/FrontPage&quot; rel=&quot;nofollow&quot;&gt;Tween&lt;/a&gt;"},{"from_user_id_str":"111826019","profile_image_url":"http://a1.twimg.com/profile_images/1121742732/DVC00052_normal.jpg","created_at":"Thu, 27 Jan 2011 12:51:12 +0000","from_user":"nijiks","id_str":"30608762859421696","metadata":{"result_type":"recent"},"to_user_id":100014282,"text":"@sanaeru  \u79c1\u3053\u3093\u306a\u5929\u6c17\u306e\u4e2d\uff64\u4e8c\u6cca\u4e09\u65e5\u3067\u660e\u65e5\u304b\u3089\u6771\u4eac\u884c\u304f\u3093\u3067\u3059\u3051\u3069\u2026\uff61\u65e5\u66dc\u65e5\u98db\u884c\u6a5f\u98db\u3076\u304b\u3057\u3089\u2026\uff1f","id":30608762859421696,"from_user_id":111826019,"to_user":"sanaeru","geo":null,"iso_language_code":"ja","to_user_id_str":"100014282","source":"&lt;a href=&quot;http://z.twipple.jp/&quot; rel=&quot;nofollow&quot;&gt;\u3064\u3044\u3063\u3077\u308b/twipple&lt;/a&gt;"},{"from_user_id_str":"164951488","profile_image_url":"http://a3.twimg.com/profile_images/799082230/twitter_normal.jpg","created_at":"Thu, 27 Jan 2011 12:47:49 +0000","from_user":"minorif_jp","id_str":"30607912309096448","metadata":{"result_type":"recent"},"to_user_id":105078670,"text":"@ecco_HIRADO \u5e73\u6238\u725b\u3063\u3066\u5143\u306f\u30aa\u30e9\u30f3\u30c0\u304b\u3089\u304d\u305f\u725b\u306a\u3093\u3060\u306d\u3002\u304a\u3044\u3057\u305d\u3046\u2026\u3002\u5e73\u6238\u306f\u3088\u304b\u6240\u305f\u3043\u3002\u3042\u305f\u3044\u3052\u3047\u3093\u5b9f\u5bb6\u3093\u65b9\u306f\u30c0\u30d6\u30eb\u706b\u5c71\u3084\u9ce5\u30a4\u30f3\u30d5\u30eb\u3067\u5927\u5909\u3084\u3063\u3069\u3002\u6771\u4eac\u3093\u826f\u304b\u3068\u3053\u306f\u5929\u6c17\u306e\u5fc3\u914d\u305b\u305a\u66ae\u3089\u305b\u308b\u3068\u3053\u3058\u3083\u3063\u3069\u3093\u3002","id":30607912309096448,"from_user_id":164951488,"to_user":"ecco_HIRADO","geo":null,"iso_language_code":"ja","to_user_id_str":"105078670","source":"&lt;a href=&quot;http://z.twipple.jp/&quot; rel=&quot;nofollow&quot;&gt;\u3064\u3044\u3063\u3077\u308b/twipple&lt;/a&gt;"},{"from_user_id_str":"10456803","profile_image_url":"http://a1.twimg.com/profile_images/145280215/vot_icon_normal.png","created_at":"Thu, 27 Jan 2011 12:43:37 +0000","from_user":"vot_","id_str":"30606853377363968","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3086\u3063\u304f\u308a\u5929\u6c17\u4e88\u5831\u3067\u3059\u3002\u6771\u4eac\u90fd,\u5927\u5cf6\u5730\u65b9\u300228\u65e5\uff08\u91d1\u66dc\u65e5\u306e\u5929\u6c17\u306f\u6674\u308c\u306e\u3061\u66c7\u308a\u3001\u6700\u9ad8\u6c17\u6e29\u306f7\u5ea6 \u6700\u4f4e\u6c17\u6e29\u306f1\u5ea6\u3067\u3057\u3087\u3046\u3002","id":30606853377363968,"from_user_id":10456803,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://voiceoftwitter.com&quot; rel=&quot;nofollow&quot;&gt;\uff56\uff4f\uff49\uff43\uff45 \uff4f\uff46 \uff54\uff57\uff49\uff54\uff54\uff45\uff52&lt;/a&gt;"},{"from_user_id_str":"23900716","profile_image_url":"http://a3.twimg.com/profile_images/1092646332/twitter_icon_normal.png","created_at":"Thu, 27 Jan 2011 12:38:00 +0000","from_user":"keiyama","id_str":"30605442639990784","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3010\u7f8e\u4eba\u5929\u6c17/\u6771\u4eac\u3011\u7f8e\u4eba\u5929\u6c17\u30ad\u30e3\u30b9\u30bf\u30fc\u306e&quot;\u30c8\u30e2\u30b3\u3055\u3093&quot;\u306b\u3088\u308b\u3068\u300c1/27(\u6728)\u306f\u304f\u3082\u308a\u306e\u3061\u6674\u3067\u3001\u964d\u6c34\u78ba\u738710%\u3001\u6700\u9ad8\u6c17\u6e29\u306f9\u2103\u3067\u6700\u4f4e\u6c17\u6e29\u306f2\u2103\u3067\u3059\u300d\u7f8e\u4eba\u5929\u6c17\u21d2http://bit.ly/djB8th http://twitpic.com/3tuekm #bt_tenki","id":30605442639990784,"from_user_id":23900716,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://bijintenki.jp&quot; rel=&quot;nofollow&quot;&gt;bijintenki.jp&lt;/a&gt;"},{"from_user_id_str":"32018516","profile_image_url":"http://a0.twimg.com/profile_images/1089472069/237_normal.jpg","created_at":"Thu, 27 Jan 2011 12:36:28 +0000","from_user":"DigJandG","id_str":"30605057460281344","metadata":{"result_type":"recent"},"to_user_id":196050661,"text":"@kosumoworld55 \u5929\u6c17\u4e88\u5831\u3092\u898b\u3066\u3044\u3064\u3082\u601d\u3046\u3093\u3060\u3002\u4f55\u3067\u6a2a\u6d5c\u3042\u305f\u308a\u306f\u3044\u3064\u3082\u597d\u3044\u5929\u6c17\u306a\u3093\u3060\u3002\u6771\u4eac\u3082\u3002\u3061\u306a\u307f\u306b\u516c\u9b5a\u306f\u3042\u3093\u307e\u308a\u597d\u304d\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u306a\u3093\u304b\u81ed\u304f\u3063\u3066\u3002\u3067\u3082\u3001\u7435\u7436\u6e56\u3067\u516c\u9b5a\u3063\u3066\u3042\u307e\u308a\u805e\u304b\u306a\u3044\u69d8\u306a\u30fb\u30fb\u30fb\u3002\u4ffa\u304c\u91e3\u308a\u3092\u3057\u306a\u3044\u304b\u3089\u304b\u306a\uff1f","id":30605057460281344,"from_user_id":32018516,"to_user":"kosumoworld55","geo":null,"iso_language_code":"ja","to_user_id_str":"196050661","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"90935348","profile_image_url":"http://a1.twimg.com/sticky/default_profile_images/default_profile_0_normal.png","created_at":"Thu, 27 Jan 2011 12:34:34 +0000","from_user":"sorakeiko","id_str":"30604575937396737","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u95a2\u6771\u5730\u65b9\u306e\u660e\u65e5\u306e\u5929\u6c17\u2015\u7d9a\u304d\u3002\u660e\u65e5\u671d\u6700\u4f4e\u6c17\u6e29\u30fb\u8ed2\u4e26\u307f\u6c37\u70b9\u4e0b\u30fb\u5b87\u90fd\u5bae\u3001\u6c34\u6238\u30de\u30a4\u30ca\u30b95\u5ea6\u30fb\u6771\u4eac\u3001\u6a2a\u6d5c1\u5ea6\u3002\u6700\u9ad8\u6c17\u6e29\u30fb\u4eca\u65e5\u3088\u308a3\u5ea6\u524d\u5f8c\u4f4e\u304f5\uff5e8\u5ea6\u30fb\u6771\u4eac\u3001\u5343\u84498\u5ea6\u3002\u5411\u3053\u3046\u4e00\u9031\u9593\u30fb\u4e7e\u71e5\u3057\u305f\u6674\u308c\u7d9a\u304f\u30fb\uff08\u571f\uff09\u4f0a\u8c46\u8af8\u5cf6\u306b\u51b7\u305f\u3044\u96e8\u3084\u96ea\u304c\u898b\u3089\u308c\u305d\u3046\u3060\u304c\u3001\u95a2\u6771\u306e\u4e7e\u3044\u305f\u72b6\u614b\u7d9a\u304f\u3002","id":30604575937396737,"from_user_id":90935348,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"6113557","profile_image_url":"http://a3.twimg.com/profile_images/1227080026/profile_red_herencia_normal.png","created_at":"Thu, 27 Jan 2011 12:33:57 +0000","from_user":"fmoto7","id_str":"30604423327653888","metadata":{"result_type":"recent"},"to_user_id":null,"text":"&quot;\u6771\u4eac\u6c34\u904b\u7528\u30bb\u30f3\u30bf\u30fc\u306f\u3001\u524d\u534a\u6226\u304c\u7d42\u308f\u3063\u305f\u3068\u3053\u308d\u3067\u4e00\u6c17\u306b\u6c34\u5727\u9ad8\u3081\u3001\u5f8c\u534a\u6226\u59cb\u307e\u308b\u3068\u6c34\u5727\u4e0b\u3052\u3001\u7d42\u308f\u308b\u3068\u307e\u305f\u3059\u3050\u4e0a\u3052\u308b\u3002\u30c6\u30ec\u30d3\u306e\u8996\u8074\u3001\u305d\u306e\u65e5\u306e\u5929\u6c17\u306a\u3069\u30e9\u30a4...&quot; http://tumblr.com/xjy1cwiwrm","id":30604423327653888,"from_user_id":6113557,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tumblr.com/&quot; rel=&quot;nofollow&quot;&gt;Tumblr&lt;/a&gt;"},{"from_user_id_str":"118092912","profile_image_url":"http://a3.twimg.com/profile_images/1225330653/____normal.PNG","created_at":"Thu, 27 Jan 2011 12:29:13 +0000","from_user":"saechuchun","id_str":"30603231042207744","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u3067\u3082\u5730\u9707\u306e\u8a71\u984c\u306e\u3068\u304d\u306e\u300c\u3082\u3057\u6771\u4eac\u3067\u76f4\u4e0b\u578b\u5730\u9707\u304c\u8d77\u304d\u305f\u3089\u300d\u3068\u304b\u5929\u6c17\u4e88\u5831\u306e\u3068\u304d\u306f\u897f\u3067\u96e8\u3060\u308d\u3046\u3068\u300c\u6771\u4eac\u3067\u306f\u301c\u65e5\u9593\u4e7e\u71e5\u3057\u3066\u307e\u3059\u306d\u30fc\u300d\u3068\u304b\u305d\u3046\u3044\u3046\u30ad\u30fc\u5c40\u306e\u95a2\u6771\u4e2d\u5fc3\u4e3b\u7fa9\u306f\u597d\u304d\u3067\u306f\u306a\u3044","id":30603231042207744,"from_user_id":118092912,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twtr.jp&quot; rel=&quot;nofollow&quot;&gt;Keitai Web&lt;/a&gt;"}],"max_id":30724239224995840,"since_id":28179956995457024,"refresh_url":"?since_id=30724239224995840&q=%E6%9D%B1%E4%BA%AC%E3%80%80%E5%A4%A9%E6%B0%97","next_page":"?page=2&max_id=30724239224995840&rpp=50&lang=ja&q=%E6%9D%B1%E4%BA%AC%E3%80%80%E5%A4%A9%E6%B0%97","results_per_page":50,"page":1,"completed_in":0.170202,"warning":"adjusted since_id to 28179956995457024 (), requested since_id was older than allowed -- since_id removed for pagination.","since_id_str":"28179956995457024","max_id_str":"30724239224995840","query":"%E6%9D%B1%E4%BA%AC%E3%80%80%E5%A4%A9%E6%B0%97"}
+ test/json-data/numbers.json view
@@ -0,0 +1,1 @@+[1.15, 1.3224999999999998, 1.5208749999999998, 1.7490062499999994, 2.0113571874999994, 2.313060765624999, 2.6600198804687487, 3.0590228625390607, 3.5178762919199196, 4.045557735707907, 4.652391396064092, 5.350250105473706, 6.152787621294761, 7.075705764488975, 8.137061629162321, 9.357620873536668, 10.761264004567169, 12.375453605252241, 14.231771646040077, 16.36653739294609, 18.821518001888, 21.644745702171196, 24.891457557496874, 28.625176191121405, 32.918952619789614, 37.856795512758055, 43.535314839671756, 50.06561206562252, 57.57545387546589, 66.21177195678577, 76.14353775030362, 87.56506841284916, 100.69982867477653, 115.804802975993, 133.17552342239193, 153.15185193575073, 176.1246297261133, 202.5433241850303, 232.9248228127848, 267.86354623470254, 308.04307816990786, 354.24953989539404, 407.3869708797031, 468.49501651165855, 538.7692689884072, 619.5846593366683, 712.5223582371685, 819.4007119727437, 942.3108187686552, 1083.6574415839534, 1246.2060578215462, 1433.136966494778, 1648.1075114689947, 1895.323638189344, 2179.622183917745, 2506.565511505407, 2882.5503382312177, 3314.9328889659, 3812.172822310785, 4383.998745657402, 5041.598557506012, 5797.838341131914, 6667.5140923017, 7667.641206146955, 8817.787387068996, 10140.455495129345, 11661.523819398746, 13410.752392308557, 15422.365251154839, 17735.720038828065, 20396.078044652273, 23455.489751350113, 26973.813214052625, 31019.885196160518, 35672.867975584595, 41023.79817192228, 47177.36789771062, 54253.97308236721, 62392.06904472228, 71750.87940143062, 82513.5113116452, 94890.53800839197, 109124.11870965076, 125492.73651609836, 144316.6469935131, 165964.14404254008, 190858.76564892105, 219487.5804962592, 252410.71757069806, 290272.32520630275, 333813.17398724816, 383885.1500853353, 441467.9225981356, 507688.1109878559, 583841.3276360342, 671417.5267814393, 772130.1557986551, 887949.6791684533, 1021142.1310437213, 1174313.4507002793, 1350460.4683053212, 1553029.5385511192, 1785983.969333787, 2053881.564733855, 2361963.7994439327, 2716258.369360523, 3123697.124764601, 3592251.6934792907, 4131089.447501184, 4750752.864626361, 5463365.794320315, 6282870.663468362, 7225301.262988616, 8309096.452436907, 9555460.920302443, 10988780.058347808, 12637097.067099977, 14532661.627164973, 16712560.871239718, 19219445.001925673, 22102361.752214525, 25417716.0150467, 29230373.417303704, 33614929.42989926, 38657168.84438414, 44455744.17104176, 51124105.79669802, 58792721.66620272, 67611629.91613312, 77753374.40355308, 89416380.56408603, 102828837.64869894, 118253163.29600377, 135991137.79040432, 156389808.45896497, 179848279.7278097, 206825521.68698114, 237849349.94002828, 273526752.4310325, 314555765.2956874, 361739130.09004045, 415999999.60354644, 478399999.5440784, 550159999.4756901, 632683999.3970436, 727586599.3066001, 836724589.20259, 962233277.5829784, 1106568269.2204251, 1272553509.6034887, 1463436536.044012, 1682952016.4506137, 1935394818.9182055, 2225704041.755936, 2559559648.019326, 2943493595.222225, 3385017634.5055585, 3892770279.681392, 4476685821.6336, 5148188694.87864, 5920416999.1104355, 6808479548.977001, 7829751481.32355, 9004214203.522081, 10354846334.050394, 11908073284.157951, 13694284276.781643, 15748426918.29889, 18110690956.04372, 20827294599.450275, 23951388789.367817, 27544097107.772987, 31675711673.938934, 36427068425.02977, 41891128688.78423, 48174797992.10186, 55401017690.91714, 63711170344.5547, 73267845896.2379, 84258022780.67358, 96896726197.77461, 111431235127.4408, 128145920396.5569, 147367808456.04044, 169472979724.44647, 194893926683.11343, 224128015685.58044, 257747218038.41748, 296409300744.1801, 340870695855.80707, 392001300234.1781, 450801495269.3048, 518421719559.70044, 596184977493.6555, 685612724117.7037, 788454632735.3593, 906722827645.6631, 1042731251792.5125, 1199140939561.3892, 1379012080495.5974, 1585863892569.937, 1823743476455.4275, 2097304997923.7415, 2411900747612.3022, 2773685859754.1475, 3189738738717.2695, 3668199549524.8594, 4218429481953.5884, 4851193904246.626, 5578872989883.619, 6415703938366.162, 7378059529121.086, 8484768458489.248, 9757483727262.635, 11221106286352.03, 12904272229304.832, 14839913063700.555, 17065900023255.637, 19625785026743.98, 22569652780755.58, 25955100697868.91, 29848365802549.246, 34325620672931.63, 39474463773871.375, 45395633339952.07, 52204978340944.88, 60035725092086.61, 69041083855899.59, 79397246434284.53, 91306833399427.2, 105002858409341.27, 120753287170742.45, 138866280246353.81, 159696222283306.88, 183650655625802.88, 211198253969673.3, 242877992065124.28, 279309690874892.9, 321206144506126.8, 369387066182045.8, 424795126109352.6, 488514395025755.5, 561791554279618.75, 646060287421561.5, 742969330534795.8, 854414730115015.0, 982576939632267.1, 1129963480577107.2, 1299458002663673.2, 1494376703063224.0, 1718533208522707.5, 1976313189801113.5, 2272760168271280.5, 2613674193511972.0, 3005725322538767.5, 3456584120919582.5, 3975071739057519.5, 4571332499916147.0, 5257032374903569.0, 6045587231139104.0, 6952425315809969.0, 7995289113181464.0, 9194582480158682.0, 1.0573769852182484e+16, 1.2159835330009856e+16, 1.3983810629511332e+16, 1.6081382223938032e+16, 1.8493589557528736e+16, 2.1267627991158044e+16, 2.4457772189831748e+16, 2.8126438018306508e+16, 3.234540372105248e+16, 3.719721427921035e+16, 4.27767964210919e+16, 4.919331588425568e+16, 5.657231326689403e+16, 6.505816025692813e+16, 7.481688429546734e+16, 8.603941693978744e+16, 9.894532948075555e+16, 1.1378712890286886e+17, 1.3085519823829918e+17, 1.5048347797404406e+17, 1.7305599967015066e+17, 1.9901439962067325e+17, 2.288665595637742e+17, 2.6319654349834032e+17, 3.026760250230913e+17, 3.48077428776555e+17, 4.002890430930382e+17, 4.603323995569939e+17, 5.29382259490543e+17, 6.087895984141244e+17, 7.00108038176243e+17, 8.051242439026793e+17, 9.258928804880812e+17, 1.0647768125612933e+18, 1.224493334445487e+18, 1.4081673346123103e+18, 1.6193924348041567e+18, 1.8623013000247798e+18, 2.1416464950284966e+18, 2.462893469282771e+18, 2.8323274896751867e+18, 3.257176613126464e+18, 3.7457531050954337e+18, 4.3076160708597484e+18, 4.95375848148871e+18, 5.696822253712016e+18, 6.551345591768818e+18, 7.53404743053414e+18, 8.66415454511426e+18, 9.963777726881399e+18, 1.1458344385913608e+19, 1.3177096043800648e+19, 1.5153660450370744e+19, 1.7426709517926355e+19, 2.0040715945615307e+19, 2.30468233374576e+19, 2.650384683807624e+19, 3.047942386378767e+19, 3.505133744335582e+19, 4.030903805985919e+19, 4.635539376883806e+19, 5.330870283416377e+19, 6.130500825928833e+19, 7.0500759498181575e+19, 8.10758734229088e+19, 9.323725443634512e+19, 1.0722284260179688e+20, 1.233062689920664e+20, 1.4180220934087634e+20, 1.6307254074200778e+20, 1.8753342185330894e+20, 2.1566343513130526e+20, 2.4801295040100103e+20, 2.8521489296115116e+20, 3.2799712690532385e+20, 3.7719669594112236e+20, 4.337762003322907e+20, 4.988426303821342e+20, 5.7366902493945437e+20, 6.597193786803724e+20, 7.586772854824282e+20, 8.724788783047925e+20, 1.0033507100505113e+21, 1.1538533165580878e+21, 1.326931314041801e+21, 1.5259710111480708e+21, 1.7548666628202813e+21, 2.0180966622433234e+21, 2.3208111615798217e+21, 2.668932835816795e+21, 3.0692727611893135e+21, 3.529663675367711e+21, 4.059113226672867e+21, 4.667980210673796e+21, 5.368177242274866e+21, 6.173403828616095e+21, 7.099414402908508e+21, 8.164326563344784e+21, 9.388975547846502e+21, 1.0797321880023475e+22, 1.2416920162026996e+22, 1.4279458186331043e+22, 1.64213769142807e+22, 1.8884583451422802e+22, 2.171727096913622e+22, 2.497486161450665e+22, 2.872109085668265e+22, 3.3029254485185042e+22, 3.798364265796279e+22, 4.368118905665721e+22, 5.0233367415155795e+22, 5.7768372527429155e+22, 6.643362840654352e+22, 7.639867266752504e+22, 8.78584735676538e+22, 1.0103724460280185e+23, 1.1619283129322213e+23, 1.3362175598720545e+23, 1.5366501938528623e+23, 1.7671477229307915e+23, 2.0322198813704103e+23, 2.3370528635759717e+23, 2.687610793112367e+23, 3.090752412079222e+23, 3.554365273891105e+23, 4.0875200649747705e+23, 4.700648074720986e+23, 5.405745285929133e+23, 6.216607078818502e+23, 7.149098140641278e+23, 8.221462861737468e+23, 9.454682290998088e+23, 1.0872884634647801e+24, 1.250381732984497e+24, 1.4379389929321714e+24, 1.653629841871997e+24, 1.9016743181527962e+24, 2.1869254658757156e+24, 2.5149642857570727e+24, 2.8922089286206334e+24, 3.326040267913728e+24, 3.824946308100787e+24, 4.3986882543159046e+24, 5.05849149246329e+24, 5.817265216332783e+24, 6.6898549987827e+24, 7.693333248600105e+24, 8.84733323589012e+24, 1.0174433221273637e+25, 1.1700598204464681e+25, 1.3455687935134384e+25, 1.547404112540454e+25, 1.779514729421522e+25, 2.04644193883475e+25, 2.353408229659962e+25, 2.7064194641089563e+25, 3.1123823837253e+25, 3.5792397412840944e+25, 4.116125702476708e+25, 4.733544557848214e+25, 5.443576241525446e+25, 6.260112677754262e+25, 7.199129579417401e+25, 8.27899901633001e+25, 9.52084886877951e+25, 1.0948976199096437e+26, 1.25913226289609e+26, 1.4480021023305035e+26, 1.665202417680079e+26, 1.9149827803320907e+26, 2.202230197381904e+26, 2.5325647269891895e+26, 2.9124494360375676e+26, 3.349316851443203e+26, 3.8517143791596826e+26, 4.429471536033635e+26, 5.09389226643868e+26, 5.857976106404481e+26, 6.736672522365153e+26, 7.747173400719924e+26, 8.909249410827912e+26, 1.0245636822452099e+27, 1.1782482345819913e+27, 1.35498546976929e+27, 1.5582332902346833e+27, 1.7919682837698857e+27, 2.0607635263353683e+27, 2.3698780552856732e+27, 2.725359763578524e+27, 3.1341637281153025e+27, 3.6042882873325974e+27, 4.1449315304324867e+27, 4.7666712599973594e+27, 5.481671948996963e+27, 6.303922741346507e+27, 7.249511152548482e+27, 8.336937825430755e+27, 9.587478499245366e+27, 1.102560027413217e+28, 1.2679440315251995e+28, 1.4581356362539794e+28, 1.6768559816920761e+28, 1.9283843789458875e+28, 2.2176420357877703e+28, 2.5502883411559357e+28, 2.932831592329326e+28, 3.3727563311787245e+28, 3.8786697808555327e+28, 4.460470247983863e+28, 5.129540785181441e+28, 5.8989719029586575e+28, 6.783817688402455e+28, 7.801390341662823e+28, 8.971598892912247e+28, 1.0317338726849081e+29, 1.1864939535876443e+29, 1.3644680466257909e+29, 1.5691382536196593e+29, 1.8045089916626083e+29, 2.0751853404119993e+29, 2.3864631414737988e+29, 2.7444326126948684e+29, 3.1560975045990984e+29, 3.629512130288963e+29, 4.173938949832307e+29, 4.800029792307153e+29, 5.520034261153225e+29, 6.348039400326208e+29, 7.300245310375139e+29, 8.39528210693141e+29, 9.65457442297112e+29, 1.1102760586416787e+30, 1.2768174674379305e+30, 1.46834008755362e+30, 1.6885911006866628e+30, 1.941879765789662e+30, 2.2331617306581113e+30, 2.568135990256828e+30, 2.9533563887953516e+30, 3.396359847114654e+30, 3.905813824181852e+30, 4.491685897809129e+30, 5.165438782480498e+30, 5.940254599852573e+30, 6.831292789830458e+30, 7.855986708305026e+30, 9.034384714550779e+30, 1.0389542421733396e+31, 1.1947973784993405e+31, 1.3740169852742412e+31, 1.5801195330653773e+31, 1.817137463025184e+31, 2.0897080824789613e+31, 2.4031642948508052e+31, 2.7636389390784257e+31, 3.1781847799401893e+31, 3.6549124969312175e+31, 4.2031493714709e+31, 4.833621777191535e+31, 5.558665043770264e+31, 6.392464800335803e+31, 7.3513345203861735e+31, 8.454034698444098e+31, 9.722139903210713e+31, 1.1180460888692319e+32, 1.2857530021996165e+32, 1.478615952529559e+32, 1.7004083454089925e+32, 1.9554695972203414e+32, 2.2487900368033926e+32, 2.586108542323901e+32, 2.974024823672486e+32, 3.420128547223359e+32, 3.933147829306862e+32, 4.523120003702891e+32, 5.2015880042583246e+32, 5.981826204897073e+32, 6.879100135631634e+32, 7.910965155976377e+32, 9.097609929372833e+32, 1.0462251418778757e+33, 1.2031589131595571e+33, 1.3836327501334904e+33, 1.591177662653514e+33, 1.8298543120515409e+33, 2.104332458859272e+33, 2.4199823276881623e+33, 2.7829796768413863e+33, 3.200426628367594e+33, 3.6804906226227334e+33, 4.232564216016143e+33, 4.867448848418564e+33, 5.597566175681348e+33, 6.437201102033549e+33, 7.402781267338582e+33, 8.513198457439368e+33, 9.790178226055273e+33, 1.1258704959963564e+34, 1.2947510703958096e+34, 1.488963730955181e+34, 1.712308290598458e+34, 1.9691545341882266e+34, 2.2645277143164603e+34, 2.604206871463929e+34, 2.994837902183518e+34, 3.4440635875110457e+34, 3.960673125637702e+34, 4.554774094483357e+34, 5.237990208655861e+34, 6.023688739954239e+34, 6.927242050947375e+34, 7.96632835858948e+34, 9.161277612377902e+34, 1.0535469254234585e+35, 1.2115789642369772e+35, 1.3933158088725236e+35, 1.6023131802034022e+35, 1.8426601572339122e+35, 2.119059180818999e+35, 2.4369180579418488e+35, 2.8024557666331258e+35, 3.2228241316280944e+35, 3.706247751372308e+35, 4.262184914078154e+35, 4.901512651189877e+35, 5.636739548868358e+35, 6.482250481198611e+35, 7.454588053378403e+35, 8.572776261385162e+35, 9.858692700592935e+35, 1.1337496605681875e+36, 1.3038121096534156e+36, 1.499383926101428e+36, 1.7242915150166418e+36, 1.982935242269138e+36, 2.2803755286095084e+36]
+ test/json-data/twitter1.json view
@@ -0,0 +1,1 @@+{"results":[{"from_user_id_str":"80430860","profile_image_url":"http://a2.twimg.com/profile_images/536455139/icon32_normal.png","created_at":"Wed, 26 Jan 2011 07:07:02 +0000","from_user":"kazu_yamamoto","id_str":"30159761706061824","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell Server Pages \u3063\u3066\u3001\u307e\u3060\u7d9a\u3044\u3066\u3044\u305f\u306e\u304b\uff01","id":30159761706061824,"from_user_id":80430860,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"}],"max_id":30159761706061824,"since_id":0,"refresh_url":"?since_id=30159761706061824&q=haskell","next_page":"?page=2&max_id=30159761706061824&rpp=1&q=haskell","results_per_page":1,"page":1,"completed_in":0.012606,"since_id_str":"0","max_id_str":"30159761706061824","query":"haskell"}
+ test/json-data/twitter10.json view
@@ -0,0 +1,1 @@+{"results":[{"from_user_id_str":"207858021","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 04:30:38 +0000","from_user":"pboudarga","id_str":"30120402839666689","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Rolla Sushi Grill (27737 Bouquet Canyon Road, #106, Btw Haskell Canyon and Rosedell Drive, Saugus) http://4sq.com/gqqdhs","id":30120402839666689,"from_user_id":207858021,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://foursquare.com&quot; rel=&quot;nofollow&quot;&gt;foursquare&lt;/a&gt;"},{"from_user_id_str":"69988683","profile_image_url":"http://a0.twimg.com/profile_images/1211955817/avatar_7888_normal.gif","created_at":"Wed, 26 Jan 2011 04:25:23 +0000","from_user":"YNK33","id_str":"30119083059978240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"hsndfile 0.5.0: Free and open source Haskell bindings for libsndfile http://bit.ly/gHaBWG Mac Os","id":30119083059978240,"from_user_id":69988683,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"81492","profile_image_url":"http://a1.twimg.com/profile_images/423894208/Picture_7_normal.jpg","created_at":"Wed, 26 Jan 2011 04:24:28 +0000","from_user":"satzz","id_str":"30118851488251904","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Emacs\u306e\u30e2\u30fc\u30c9\u8868\u793a\u304c\u4eca(Ruby Controller Outputz RoR Flymake REl hs)\u3068\u306a\u3063\u3066\u3066\u3088\u304f\u308f\u304b\u3089\u306a\u3044\u3093\u3060\u3051\u3069\u6700\u5f8c\u306eREl\u3068\u304bhs\u3063\u3066\u4f55\u3060\u308d\u3046\u2026haskell\u3068\u304b2\u5e74\u4ee5\u4e0a\u66f8\u3044\u3066\u306a\u3044\u3051\u3069\u2026","id":30118851488251904,"from_user_id":81492,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"9518356","profile_image_url":"http://a2.twimg.com/profile_images/119165723/ocaml-icon_normal.png","created_at":"Wed, 26 Jan 2011 04:19:19 +0000","from_user":"planet_ocaml","id_str":"30117557788741632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I so miss #haskell type classes in #ocaml - i want to do something like refinement. Also why does ocaml not have... http://bit.ly/geYRwt","id":30117557788741632,"from_user_id":9518356,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"218059","profile_image_url":"http://a1.twimg.com/profile_images/1053837723/twitter-icon9_normal.jpg","created_at":"Wed, 26 Jan 2011 04:16:32 +0000","from_user":"aprikip","id_str":"30116854940835840","metadata":{"result_type":"recent"},"to_user_id":null,"text":"yatex-mode\u3084haskell-mode\u306e\u3053\u3068\u3067\u3059\u306d\u3001\u308f\u304b\u308a\u307e\u3059\u3002","id":30116854940835840,"from_user_id":218059,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://sites.google.com/site/yorufukurou/&quot; rel=&quot;nofollow&quot;&gt;YoruFukurou&lt;/a&gt;"},{"from_user_id_str":"216363","profile_image_url":"http://a1.twimg.com/profile_images/72454310/Tim-Avatar_normal.png","created_at":"Wed, 26 Jan 2011 04:15:30 +0000","from_user":"dysinger","id_str":"30116594684264448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell in Hawaii tonight for me... #fun","id":30116594684264448,"from_user_id":216363,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.nambu.com/&quot; rel=&quot;nofollow&quot;&gt;Nambu&lt;/a&gt;"},{"from_user_id_str":"1774820","profile_image_url":"http://a2.twimg.com/profile_images/61169291/dan_desert_thumb_normal.jpg","created_at":"Wed, 26 Jan 2011 04:13:36 +0000","from_user":"DanMil","id_str":"30116117682851840","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire @tomheon Haskell isn't a language, it's a belief system.  A seductive one...","id":30116117682851840,"from_user_id":1774820,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"659256","profile_image_url":"http://a0.twimg.com/profile_images/746976711/angular-final_normal.jpg","created_at":"Wed, 26 Jan 2011 04:11:06 +0000","from_user":"djspiewak","id_str":"30115488931520512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"One of the very nice things about Haskell as opposed to SML is the reduced proliferation of identifiers (e.g. andb, orb, etc). #typeclasses","id":30115488931520512,"from_user_id":659256,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 04:06:12 +0000","from_user":"listwarenet","id_str":"30114255890026496","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84752-re-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Re: Haskell-c","id":30114255890026496,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://1e10.org/cloud/&quot; rel=&quot;nofollow&quot;&gt;1e10&lt;/a&gt;"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 04:01:29 +0000","from_user":"ojrac","id_str":"30113067333324800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tomheon: @ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30113067333324800,"from_user_id":1594784,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"}],"max_id":30120402839666689,"since_id":0,"refresh_url":"?since_id=30120402839666689&q=haskell","next_page":"?page=2&max_id=30120402839666689&rpp=10&q=haskell","results_per_page":10,"page":1,"completed_in":0.012714,"since_id_str":"0","max_id_str":"30120402839666689","query":"haskell"}
+ test/json-data/twitter100.json view
@@ -0,0 +1,1 @@+{"results":[{"from_user_id_str":"3646730","profile_image_url":"http://a3.twimg.com/profile_images/404973767/avatar_normal.jpg","created_at":"Wed, 26 Jan 2011 04:35:07 +0000","from_user":"nicolaslara","id_str":"30121530767708160","metadata":{"result_type":"recent"},"to_user_id":18616016,"text":"@josej30 Python y Clojure. Obviamente son diferentes, y cada uno tiene sus ventajas y desventajas. De Haskell faltar\u00eda pattern matching","id":30121530767708160,"from_user_id":3646730,"to_user":"josej30","geo":null,"iso_language_code":"es","to_user_id_str":"18616016","source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"207858021","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 04:30:38 +0000","from_user":"pboudarga","id_str":"30120402839666689","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Rolla Sushi Grill (27737 Bouquet Canyon Road, #106, Btw Haskell Canyon and Rosedell Drive, Saugus) http://4sq.com/gqqdhs","id":30120402839666689,"from_user_id":207858021,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://foursquare.com&quot; rel=&quot;nofollow&quot;&gt;foursquare&lt;/a&gt;"},{"from_user_id_str":"69988683","profile_image_url":"http://a0.twimg.com/profile_images/1211955817/avatar_7888_normal.gif","created_at":"Wed, 26 Jan 2011 04:25:23 +0000","from_user":"YNK33","id_str":"30119083059978240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"hsndfile 0.5.0: Free and open source Haskell bindings for libsndfile http://bit.ly/gHaBWG Mac Os","id":30119083059978240,"from_user_id":69988683,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"81492","profile_image_url":"http://a1.twimg.com/profile_images/423894208/Picture_7_normal.jpg","created_at":"Wed, 26 Jan 2011 04:24:28 +0000","from_user":"satzz","id_str":"30118851488251904","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Emacs\u306e\u30e2\u30fc\u30c9\u8868\u793a\u304c\u4eca(Ruby Controller Outputz RoR Flymake REl hs)\u3068\u306a\u3063\u3066\u3066\u3088\u304f\u308f\u304b\u3089\u306a\u3044\u3093\u3060\u3051\u3069\u6700\u5f8c\u306eREl\u3068\u304bhs\u3063\u3066\u4f55\u3060\u308d\u3046\u2026haskell\u3068\u304b2\u5e74\u4ee5\u4e0a\u66f8\u3044\u3066\u306a\u3044\u3051\u3069\u2026","id":30118851488251904,"from_user_id":81492,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"9518356","profile_image_url":"http://a2.twimg.com/profile_images/119165723/ocaml-icon_normal.png","created_at":"Wed, 26 Jan 2011 04:19:19 +0000","from_user":"planet_ocaml","id_str":"30117557788741632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I so miss #haskell type classes in #ocaml - i want to do something like refinement. Also why does ocaml not have... http://bit.ly/geYRwt","id":30117557788741632,"from_user_id":9518356,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"218059","profile_image_url":"http://a1.twimg.com/profile_images/1053837723/twitter-icon9_normal.jpg","created_at":"Wed, 26 Jan 2011 04:16:32 +0000","from_user":"aprikip","id_str":"30116854940835840","metadata":{"result_type":"recent"},"to_user_id":null,"text":"yatex-mode\u3084haskell-mode\u306e\u3053\u3068\u3067\u3059\u306d\u3001\u308f\u304b\u308a\u307e\u3059\u3002","id":30116854940835840,"from_user_id":218059,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://sites.google.com/site/yorufukurou/&quot; rel=&quot;nofollow&quot;&gt;YoruFukurou&lt;/a&gt;"},{"from_user_id_str":"216363","profile_image_url":"http://a1.twimg.com/profile_images/72454310/Tim-Avatar_normal.png","created_at":"Wed, 26 Jan 2011 04:15:30 +0000","from_user":"dysinger","id_str":"30116594684264448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell in Hawaii tonight for me... #fun","id":30116594684264448,"from_user_id":216363,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.nambu.com/&quot; rel=&quot;nofollow&quot;&gt;Nambu&lt;/a&gt;"},{"from_user_id_str":"1774820","profile_image_url":"http://a2.twimg.com/profile_images/61169291/dan_desert_thumb_normal.jpg","created_at":"Wed, 26 Jan 2011 04:13:36 +0000","from_user":"DanMil","id_str":"30116117682851840","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire @tomheon Haskell isn't a language, it's a belief system.  A seductive one...","id":30116117682851840,"from_user_id":1774820,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"659256","profile_image_url":"http://a0.twimg.com/profile_images/746976711/angular-final_normal.jpg","created_at":"Wed, 26 Jan 2011 04:11:06 +0000","from_user":"djspiewak","id_str":"30115488931520512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"One of the very nice things about Haskell as opposed to SML is the reduced proliferation of identifiers (e.g. andb, orb, etc). #typeclasses","id":30115488931520512,"from_user_id":659256,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 04:06:12 +0000","from_user":"listwarenet","id_str":"30114255890026496","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84752-re-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Re: Haskell-c","id":30114255890026496,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://1e10.org/cloud/&quot; rel=&quot;nofollow&quot;&gt;1e10&lt;/a&gt;"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 04:01:29 +0000","from_user":"ojrac","id_str":"30113067333324800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tomheon: @ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30113067333324800,"from_user_id":1594784,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"207589736","profile_image_url":"http://a3.twimg.com/profile_images/1225527428/headshot_1_normal.jpg","created_at":"Wed, 26 Jan 2011 04:00:13 +0000","from_user":"ashleevelazq101","id_str":"30112747555397632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/dONnpn","id":30112747555397632,"from_user_id":207589736,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"Hackage","id_str":"30112192346984448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112192346984448,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"aapnoot","id_str":"30112191881420800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112191881420800,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"8530482","profile_image_url":"http://a2.twimg.com/profile_images/137867266/n608671563_7396_normal.jpg","created_at":"Wed, 26 Jan 2011 03:50:12 +0000","from_user":"jeffmclamb","id_str":"30110229207187456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Angel - daemon to run and monitor processes like daemontools or god, written in Haskell http://ff.im/-wNyLk","id":30110229207187456,"from_user_id":8530482,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://friendfeed.com&quot; rel=&quot;nofollow&quot;&gt;FriendFeed&lt;/a&gt;"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:46:01 +0000","from_user":"tomheon","id_str":"30109174645919744","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30109174645919744,"from_user_id":177539201,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 03:44:34 +0000","from_user":"ojrac","id_str":"30108808684503040","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire @tomheon Why are you making me curious about Haskell? I LIKE not knowing what monad means!!","id":30108808684503040,"from_user_id":1594784,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"23750094","profile_image_url":"http://a0.twimg.com/profile_images/951373780/Moeinthecar_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:54 +0000","from_user":"shokalshab","id_str":"30108140443795456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Magnitude Cheer @ Gymnastics Olympica USA (7735 Haskell Ave., btw Saticoy &amp; Strathern, Van Nuys) http://4sq.com/gmXfaL","id":30108140443795456,"from_user_id":23750094,"geo":null,"iso_language_code":"en","place":{"id":"4e4a2a2f86cb2946","type_":"poi","full_name":"Gymnastics Olympica USA, Van Nuys"},"to_user_id_str":null,"source":"&lt;a href=&quot;http://foursquare.com&quot; rel=&quot;nofollow&quot;&gt;foursquare&lt;/a&gt;"},{"from_user_id_str":"8135112","profile_image_url":"http://a0.twimg.com/profile_images/1165240350/LIMITED_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:35 +0000","from_user":"Claricei","id_str":"30108059208515584","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @kristenmchugh22: @KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30108059208515584,"from_user_id":8135112,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:40:02 +0000","from_user":"chewedwire","id_str":"30107670367182848","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon Cool, I'll take a look. I feel like I should mention this: http://bit.ly/hVstDM","id":30107670367182848,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"8679778","profile_image_url":"http://a3.twimg.com/profile_images/1195318056/me_nyc_12_18_10_icon_normal.jpg","created_at":"Wed, 26 Jan 2011 03:38:42 +0000","from_user":"kristenmchugh22","id_str":"30107332381777920","metadata":{"result_type":"recent"},"to_user_id":756269,"text":"@KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30107332381777920,"from_user_id":8679778,"to_user":"KeithOlbermann","geo":null,"iso_language_code":"en","to_user_id_str":"756269","source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"103316559","profile_image_url":"http://a1.twimg.com/profile_images/1179458751/bc3beab4-d59d-4e78-b13b-50747986cfa2_normal.png","created_at":"Wed, 26 Jan 2011 03:36:15 +0000","from_user":"cityslikr","id_str":"30106719153557504","metadata":{"result_type":"recent"},"to_user_id":null,"text":"&quot;Social safety net into a hammock.&quot; So says Eddie Haskell with the GOP response. #SOTU","id":30106719153557504,"from_user_id":103316559,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://blackberry.com/twitter&quot; rel=&quot;nofollow&quot;&gt;Twitter for BlackBerry\u00ae&lt;/a&gt;"},{"from_user_id_str":"169063143","profile_image_url":"http://a0.twimg.com/profile_images/1160506212/9697_1_normal.gif","created_at":"Wed, 26 Jan 2011 03:31:52 +0000","from_user":"wrkforce_safety","id_str":"30105614919143424","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/gA60C1","id":30105614919143424,"from_user_id":169063143,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:29:40 +0000","from_user":"tomheon","id_str":"30105060960632832","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire Great book on Haskell: http://oreilly.com/catalog/9780596514983","id":30105060960632832,"from_user_id":177539201,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"782692","profile_image_url":"http://a0.twimg.com/profile_images/1031304589/Profile.2007.1_normal.jpg","created_at":"Wed, 26 Jan 2011 03:29:19 +0000","from_user":"turnageb","id_str":"30104974591533057","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @ovillalon: Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104974591533057,"from_user_id":782692,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:28:04 +0000","from_user":"chewedwire","id_str":"30104657267265536","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon I always loved the pattern matching in SML and it looks like Haskell is MUCH better at it. I'm messing around now at tryhaskell.org","id":30104657267265536,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"12834082","profile_image_url":"http://a3.twimg.com/profile_images/1083036140/mugshot_normal.png","created_at":"Wed, 26 Jan 2011 03:28:01 +0000","from_user":"ovillalon","id_str":"30104647213518848","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104647213518848,"from_user_id":12834082,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:26:02 +0000","from_user":"goodfox","id_str":"30104146455560192","metadata":{"result_type":"recent"},"to_user_id":10226179,"text":"@billykeene22 Bordeaux is one of my heroes. I was so excited when he accepted the invitation to campus. He's been a great friend to Haskell.","id":30104146455560192,"from_user_id":13540930,"to_user":"billykeene22","geo":null,"iso_language_code":"en","to_user_id_str":"10226179","source":"&lt;a href=&quot;http://www.ubertwitter.com/bb/download.php&quot; rel=&quot;nofollow&quot;&gt;\u00dcberTwitter&lt;/a&gt;"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 03:25:18 +0000","from_user":"josej30","id_str":"30103962313031681","metadata":{"result_type":"recent"},"to_user_id":14870909,"text":"@cris7ian Ahh bueno multiparadigma ya es respetable :) Empezar\u00e9 a explotar la parte funcional de los lenguajes ahora #Haskell","id":30103962313031681,"from_user_id":18616016,"to_user":"Cris7ian","geo":null,"iso_language_code":"es","to_user_id_str":"14870909","source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"14870909","profile_image_url":"http://a2.twimg.com/profile_images/1176930429/oso_yo_normal.png","created_at":"Wed, 26 Jan 2011 03:23:43 +0000","from_user":"Cris7ian","id_str":"30103562360983553","metadata":{"result_type":"recent"},"to_user_id":18616016,"text":"@josej30 hahaha no, es multiparadigma y es bastante lazy. Nothing like haskell, pero s\u00ed, el de Flash","id":30103562360983553,"from_user_id":14870909,"to_user":"josej30","geo":null,"iso_language_code":"es","to_user_id_str":"18616016","source":"&lt;a href=&quot;http://www.echofon.com/&quot; rel=&quot;nofollow&quot;&gt;Echofon&lt;/a&gt;"},{"from_user_id_str":"2421643","profile_image_url":"http://a0.twimg.com/profile_images/1190361665/ernestgrumbles-17_normal.jpg","created_at":"Wed, 26 Jan 2011 03:20:24 +0000","from_user":"ernestgrumbles","id_str":"30102730756333568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Wow... WolframAlpha did not know who Eddie Haskell is.  Guess I'll never use that &quot;knowledge engine&quot; again.","id":30102730756333568,"from_user_id":2421643,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:14:21 +0000","from_user":"chewedwire","id_str":"30101204428132352","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon How is Haskell better/different from CL or Scheme? I honestly don't know, although I'm becoming more curious.","id":30101204428132352,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:06:54 +0000","from_user":"goodfox","id_str":"30099329809129473","metadata":{"result_type":"recent"},"to_user_id":null,"text":"A day of vision &amp; speeches. #SOTU now. And a wonderful Haskell Convocation address earlier today by Sinte Gleske President Lionel Bordeaux.","id":30099329809129473,"from_user_id":13540930,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.ubertwitter.com/bb/download.php&quot; rel=&quot;nofollow&quot;&gt;\u00dcberTwitter&lt;/a&gt;"},{"from_user_id_str":"119185220","profile_image_url":"http://a0.twimg.com/profile_images/1089027228/dfg_normal.jpg","created_at":"Wed, 26 Jan 2011 03:03:38 +0000","from_user":"LaLiciouz_03","id_str":"30098510623805440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"The Game with the girl room 330 Haskell follow us...","id":30098510623805440,"from_user_id":119185220,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 02:57:25 +0000","from_user":"josej30","id_str":"30096946144215040","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Voy a extra\u00f1ar Haskell cuando regrese al mundo imperativo. Hay alg\u00fan lenguaje imperativo que tenga este poder funcional? #ci3661","id":30096946144215040,"from_user_id":18616016,"geo":null,"iso_language_code":"es","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 02:55:32 +0000","from_user":"Hackage","id_str":"30096471814574080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"comonad-transformers 0.9.0, added by EdwardKmett: Haskell 98 comonad transformers http://bit.ly/h6xIsf","id":30096471814574080,"from_user_id":17671137,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 02:48:12 +0000","from_user":"tomheon","id_str":"30094626920603649","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Every time I look at Haskell I love it more.","id":30094626920603649,"from_user_id":177539201,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"60792568","profile_image_url":"http://a0.twimg.com/profile_images/1203647517/glenda-flash_normal.jpg","created_at":"Wed, 26 Jan 2011 02:40:42 +0000","from_user":"r_takaishi","id_str":"30092735935422464","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u3088\u308aD\u8a00\u8a9e\u304c\u4e0a\u3068\u306f\u601d\u308f\u306a\u304b\u3063\u305f\uff0e http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html","id":30092735935422464,"from_user_id":60792568,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twmode.sf.net/&quot; rel=&quot;nofollow&quot;&gt;twmode&lt;/a&gt;"},{"from_user_id_str":"160145510","profile_image_url":"http://a0.twimg.com/profile_images/1218108166/going_galt_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:31 +0000","from_user":"wtp1787","id_str":"30092439653974018","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @KLSouth: Eddie Haskell Goes to Washington...  &quot;You look really nice tonight, Ms Cleaver&quot;","id":30092439653974018,"from_user_id":160145510,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"96616016","profile_image_url":"http://a1.twimg.com/profile_images/1196978169/Picture0002_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:20 +0000","from_user":"MelissaRNMBA","id_str":"30092392203816960","metadata":{"result_type":"recent"},"to_user_id":14862975,"text":"@KLSouth At least Eddie Haskell was entertaining.","id":30092392203816960,"from_user_id":96616016,"to_user":"KLSouth","geo":null,"iso_language_code":"en","to_user_id_str":"14862975","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"14862975","profile_image_url":"http://a0.twimg.com/profile_images/421596393/kls_4_normal.JPG","created_at":"Wed, 26 Jan 2011 02:38:29 +0000","from_user":"KLSouth","id_str":"30092178327871489","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Eddie Haskell Goes to Washington...  &quot;You look really nice tonight, Ms Cleaver&quot;","id":30092178327871489,"from_user_id":14862975,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 02:36:17 +0000","from_user":"listwarenet","id_str":"30091626869161984","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84641-haskell-beginners-wildcards-in-expressions.html Haskell-beginners -  Wild","id":30091626869161984,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://1e10.org/cloud/&quot; rel=&quot;nofollow&quot;&gt;1e10&lt;/a&gt;"},{"from_user_id_str":"24538048","profile_image_url":"http://a2.twimg.com/profile_images/1117267605/rope_normal.jpg","created_at":"Wed, 26 Jan 2011 02:23:14 +0000","from_user":"dbph","id_str":"30088341030440960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @dnene: Skilled Calisthenics. Haskell code that outputs python which spits ruby which emits the haskell source. http://j.mp/YlQUL via @mfeathers","id":30088341030440960,"from_user_id":24538048,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:58:31 +0000","from_user":"YubaVetTech","id_str":"30082124207886336","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigious Hayward Award for \u2018Excellence in Education\u2019. This award honors... http://fb.me/QgQCxd74","id":30082124207886336,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.facebook.com/twitter&quot; rel=&quot;nofollow&quot;&gt;Facebook&lt;/a&gt;"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:56:04 +0000","from_user":"YubaVetTech","id_str":"30081505476743168","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigous Haward Award for Excellence in Education. This award honors... http://fb.me/PC9mYmCR","id":30081505476743168,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.facebook.com/twitter&quot; rel=&quot;nofollow&quot;&gt;Facebook&lt;/a&gt;"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:43:50 +0000","from_user":"Verus","id_str":"30078427155406848","metadata":{"result_type":"recent"},"to_user_id":79273052,"text":"@kami_joe \u3044\u3084\uff0c\u8ab2\u984c\u306f\u89e3\u6c7a\u5bfe\u8c61(\u30d1\u30ba\u30eb\u3068\u304b)\u3092\u4e0e\u3048\u3089\u308c\u3066\uff0c\u554f\u984c\u5b9a\u7fa9\u3068\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0(\u6307\u5b9a\u8a00\u8a9e\u306fC++\u3082\u3057\u304f\u306fJava)\u3068\u3044\u3046\u3044\u308f\u3070\u666e\u901a\u306a\u8ab2\u984c\u3067\u306f\u3042\u308b\u3093\u3060\u3051\u3069\uff0e\u95a2\u6570\u578b\u8a00\u8a9e\u306fHaskell\u306e\u6388\u696d\u304c\u307e\u305f\u5225\u306b\u3042\u308b\u306e\uff0e","id":30078427155406848,"from_user_id":2331498,"to_user":"kami_joe","geo":null,"iso_language_code":"ja","to_user_id_str":"79273052","source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"79151233","profile_image_url":"http://a2.twimg.com/a/1295051201/images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 01:40:37 +0000","from_user":"cz_newdrafts","id_str":"30077617361125376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell programming language http://bit.ly/gpPAwB","id":30077617361125376,"from_user_id":79151233,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://tommorris.org/&quot; rel=&quot;nofollow&quot;&gt;tommorris' hacksample&lt;/a&gt;"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:57 +0000","from_user":"Verus","id_str":"30068139416879104","metadata":{"result_type":"recent"},"to_user_id":9252720,"text":"@shukukei Java\u3068C\u306f\u3042\u308b\u7a0b\u5ea6\u66f8\u3051\u3066\u3042\u305f\u308a\u307e\u3048\u306a\u3068\u3053\u308d\u304c\u3042\u308b\u304b\u3089\u306a\u30fc\uff0ePython\u306f\u500b\u4eba\u7684\u306b\u611f\u899a\u304c\u5408\u308f\u306a\u3044\uff0e\u611f\u899a\u306a\u306e\u3067\uff0c\u3082\u3046\u3069\u3046\u3057\u3088\u3046\u3082\u306a\u3044\uff57 \u3044\u307e\u306fScala\u3068Haskell\u3092\u3082\u3063\u3068\u6975\u3081\u305f\u3044\u3068\u3053\u308d\uff0e","id":30068139416879104,"from_user_id":2331498,"to_user":"shukukei","geo":null,"iso_language_code":"ja","to_user_id_str":"9252720","source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"2781460","profile_image_url":"http://a0.twimg.com/profile_images/82526625/.joeyicon_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:35 +0000","from_user":"joeyhess","id_str":"30068046538219520","metadata":{"result_type":"recent"},"to_user_id":null,"text":"just figured out that I can use parameterized types to remove a dependency loop in git-annex's type definitions. whee #haskell","id":30068046538219520,"from_user_id":2781460,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://identi.ca&quot; rel=&quot;nofollow&quot;&gt;identica&lt;/a&gt;"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 00:54:22 +0000","from_user":"listwarenet","id_str":"30065977920061440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84466-haskell-beginners-bytestring-question.html Haskell-beginners -  Bytestrin","id":30065977920061440,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://1e10.org/cloud/&quot; rel=&quot;nofollow&quot;&gt;1e10&lt;/a&gt;"},{"from_user_id_str":"1291845","profile_image_url":"http://a0.twimg.com/profile_images/1225743404/ThinOxygen-small-opaque-solidarity_normal.png","created_at":"Wed, 26 Jan 2011 00:52:07 +0000","from_user":"_aaron_","id_str":"30065412242669568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"wanted: librly licensed high level native compiled lang with min runtime (otherwise cobra/mono would be perfect) for win. lua? haskell? ooc?","id":30065412242669568,"from_user_id":1291845,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"5912444","profile_image_url":"http://a2.twimg.com/profile_images/546261026/ssf0xg11_normal.jpg","created_at":"Wed, 26 Jan 2011 00:45:45 +0000","from_user":"shelarcy","id_str":"30063810773516288","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @Hackage: download 0.3.1.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/eHfiJB","id":30063810773516288,"from_user_id":5912444,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"135993","profile_image_url":"http://a2.twimg.com/profile_images/1190667086/myface2010small_normal.jpg","created_at":"Wed, 26 Jan 2011 00:41:00 +0000","from_user":"kudzu_naoki","id_str":"30062613287141376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u9b54\u6cd5Haskell\u5c11\u5973\u5019\u88dc\u3092\u63a2\u3059\u306e\u3082\u5927\u5909\u306a\u3093\u3060","id":30062613287141376,"from_user_id":135993,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"52620546","profile_image_url":"http://a1.twimg.com/profile_images/434693356/twitter-icon_normal.png","created_at":"Wed, 26 Jan 2011 00:40:25 +0000","from_user":"omasanori","id_str":"30062465656033280","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u9b54\u6cd5Haskell\u5c11\u5973\u306e\u4e00\u65e5\u306fGHC HEAD\u306e\u30d3\u30eb\u30c9\u304b\u3089\u59cb\u307e\u308b","id":30062465656033280,"from_user_id":52620546,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.movatwi.jp&quot; rel=&quot;nofollow&quot;&gt;www.movatwi.jp&lt;/a&gt;"},{"from_user_id_str":"52620546","profile_image_url":"http://a1.twimg.com/profile_images/434693356/twitter-icon_normal.png","created_at":"Wed, 26 Jan 2011 00:37:12 +0000","from_user":"omasanori","id_str":"30061656331526144","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u50d5\u3068\u5951\u7d04\u3057\u3066\u9b54\u6cd5Haskell\u5c11\u5973\u306b\u306a\u308d\u3046\u3088\uff01","id":30061656331526144,"from_user_id":52620546,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"135993","profile_image_url":"http://a2.twimg.com/profile_images/1190667086/myface2010small_normal.jpg","created_at":"Wed, 26 Jan 2011 00:35:42 +0000","from_user":"kudzu_naoki","id_str":"30061282665168896","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u50d5\u3068\u5951\u7d04\u3057\u3066\u9b54\u6cd5Haskell\u5c11\u5973\u306b\u306a\u308d\u3046\u3088\uff01","id":30061282665168896,"from_user_id":135993,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"1631333","profile_image_url":"http://a1.twimg.com/profile_images/81268862/profile300_normal.jpg","created_at":"Wed, 26 Jan 2011 00:30:02 +0000","from_user":"qnighy","id_str":"30059855884582913","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tanakh: \u50d5\u3068\u5951\u7d04\u3057\u3066\u9b54\u6cd5Haskell\u5c11\u5973\u306b\u306a\u308d\u3046\u3088\uff01","id":30059855884582913,"from_user_id":1631333,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"9093754","profile_image_url":"http://a1.twimg.com/profile_images/99435906/PHD_3d_col_blk_normal.jpg","created_at":"Wed, 26 Jan 2011 00:26:20 +0000","from_user":"phdwine","id_str":"30058925516656640","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Last weekend of Tri Nations Tasting with PHD wines at Haskell Vineyards. Hope you didn't miss the Pinot Noir tasting last week !","id":30058925516656640,"from_user_id":9093754,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"2119923","profile_image_url":"http://a2.twimg.com/profile_images/1096701078/djayprofile_normal.jpg","created_at":"Wed, 26 Jan 2011 00:21:14 +0000","from_user":"djay75","id_str":"30057639543050240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @dnene: Skilled Calisthenics. Haskell code that outputs python which spits ruby which emits the haskell source. http://j.mp/YlQUL via @mfeathers","id":30057639543050240,"from_user_id":2119923,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"134323731","profile_image_url":"http://a2.twimg.com/profile_images/1225818824/IMG00518-20110125-1547_normal.jpg","created_at":"Wed, 26 Jan 2011 00:19:30 +0000","from_user":"PrinceOfBrkeley","id_str":"30057205554216960","metadata":{"result_type":"recent"},"to_user_id":167093027,"text":"@PayThaPrince go to haskell.","id":30057205554216960,"from_user_id":134323731,"to_user":"PayThaPrince","geo":null,"iso_language_code":"en","to_user_id_str":"167093027","source":"&lt;a href=&quot;http://blackberry.com/twitter&quot; rel=&quot;nofollow&quot;&gt;Twitter for BlackBerry\u00ae&lt;/a&gt;"},{"from_user_id_str":"705857","profile_image_url":"http://a1.twimg.com/profile_images/429483912/ben_twitter_normal.jpg","created_at":"Wed, 26 Jan 2011 00:03:28 +0000","from_user":"bennadel","id_str":"30053166972141569","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Using #Homebrew to install Haskell - the last of the Seven Languages (in Seven Weeks) http://bit.ly/eA9Cv1 This has been some journey.","id":30053166972141569,"from_user_id":705857,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"251466","profile_image_url":"http://a2.twimg.com/profile_images/1194100934/pass_normal.jpg","created_at":"Wed, 26 Jan 2011 00:02:54 +0000","from_user":"simonszu","id_str":"30053025502466048","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Ouh yeah! Ich werde doch produktiv sein, diese Semesterferien. Ich werde funktional Programmieren lernen. #haskell, Baby.","id":30053025502466048,"from_user_id":251466,"geo":null,"iso_language_code":"de","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.echofon.com/&quot; rel=&quot;nofollow&quot;&gt;Echofon&lt;/a&gt;"},{"from_user_id_str":"357786","profile_image_url":"http://a0.twimg.com/profile_images/612044841/FM_2010_normal.jpg","created_at":"Tue, 25 Jan 2011 23:59:13 +0000","from_user":"diligiant","id_str":"30052100973006848","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @paulrbrown: &quot;...we only discovered a single bug after compilation.&quot; (http://t.co/K0wlEYz) #haskell","id":30052100973006848,"from_user_id":357786,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"101597523","profile_image_url":"http://a1.twimg.com/profile_images/1206183256/2010-12-12-204902_normal.jpg","created_at":"Tue, 25 Jan 2011 23:54:46 +0000","from_user":"wlad_kent","id_str":"30050977964892160","metadata":{"result_type":"recent"},"to_user_id":86297184,"text":"@Nilson_Neto Isso eh bem basico. quando vc estiver estudando recurs\u00e3o em Haskell, ai vc vai ver oq eh papo de nerd - kkk - 1\u00ba periodo isso.","id":30050977964892160,"from_user_id":101597523,"to_user":"Nilson_Neto","geo":null,"iso_language_code":"pt","to_user_id_str":"86297184","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Tue, 25 Jan 2011 23:51:22 +0000","from_user":"listwarenet","id_str":"30050123383832577","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84336-haskell-cafe-monomorphic-let-bindings-and-darcs.html Haskell-cafe -  Monomorph","id":30050123383832577,"from_user_id":144546280,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://1e10.org/cloud/&quot; rel=&quot;nofollow&quot;&gt;1e10&lt;/a&gt;"},{"from_user_id_str":"5776901","profile_image_url":"http://a0.twimg.com/profile_images/472682157/lucabw_normal.JPG","created_at":"Tue, 25 Jan 2011 23:48:40 +0000","from_user":"lsbardel","id_str":"30049446469312512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Very interesting technology stack these guys use http://bit.ly/ghAjS7 #python #redis #haskell","id":30049446469312512,"from_user_id":5776901,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"3005901","profile_image_url":"http://a0.twimg.com/profile_images/278943006/Lone_Pine_Peak_-_Peter_200x200_normal.jpg","created_at":"Tue, 25 Jan 2011 23:45:48 +0000","from_user":"pmonks","id_str":"30048721110573056","metadata":{"result_type":"recent"},"to_user_id":203834278,"text":"@techielicous Haskell: http://bit.ly/gy3oFi  ;-)","id":30048721110573056,"from_user_id":3005901,"to_user":"techielicous","geo":null,"iso_language_code":"en","to_user_id_str":"203834278","source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"162697074","profile_image_url":"http://a2.twimg.com/profile_images/826205838/ryan3_normal.jpg","created_at":"Tue, 25 Jan 2011 23:44:47 +0000","from_user":"TheRonaldMCD","id_str":"30048468781244416","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Aldi Food Market (4122 Gaston Ave, Haskell, Dallas) http://4sq.com/ekqRY7","id":30048468781244416,"from_user_id":162697074,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://foursquare.com&quot; rel=&quot;nofollow&quot;&gt;foursquare&lt;/a&gt;"},{"from_user_id_str":"203834278","profile_image_url":"http://a0.twimg.com/profile_images/1223375080/me_normal.jpg","created_at":"Tue, 25 Jan 2011 23:44:04 +0000","from_user":"techielicous","id_str":"30048286589067264","metadata":{"result_type":"recent"},"to_user_id":3005901,"text":"@pmonks I was thinking Haskell or Scheme","id":30048286589067264,"from_user_id":203834278,"to_user":"pmonks","geo":null,"iso_language_code":"en","to_user_id_str":"3005901","source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"537690","profile_image_url":"http://a3.twimg.com/profile_images/45665122/nushiostamp_normal.jpg","created_at":"Tue, 25 Jan 2011 23:38:14 +0000","from_user":"nushio","id_str":"30046818658164737","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u305d\u3046\u3044\u3084\u5951\u7d04\u306b\u3088\u308b\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0\u3068\u304b\u3042\u3063\u305f\u306a\u3002Haskell\u306a\u3093\u304b\u3088\u308a\u3042\u3063\u3061\u306e\u65b9\u304c\u9b54\u6cd5\u5c11\u5973\u547c\u3070\u308f\u308a\u306b\u3075\u3055\u308f\u3057\u3044\u3002","id":30046818658164737,"from_user_id":537690,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"181192","profile_image_url":"http://a2.twimg.com/profile_images/1089890701/q530888600_9828_normal.jpg","created_at":"Tue, 25 Jan 2011 23:38:03 +0000","from_user":"aodag","id_str":"30046772223016960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @omasanori: \u300c\u3082\u3046\u4f55\u5e74\u3082Haskell\u306e\u3053\u3068\u3057\u304b\u8003\u3048\u3066\u306a\u304b\u3063\u305f\u304b\u3089\u306a\u3001\u30eb\u30fc\u30d7\u306e\u4f7f\u3044\u65b9\u5fd8\u308c\u3066\u305f\u300d","id":30046772223016960,"from_user_id":181192,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.movatwi.jp&quot; rel=&quot;nofollow&quot;&gt;www.movatwi.jp&lt;/a&gt;"},{"from_user_id_str":"5886055","profile_image_url":"http://a3.twimg.com/profile_images/85531669/ichi_normal.jpg","created_at":"Tue, 25 Jan 2011 23:37:53 +0000","from_user":"kanaya","id_str":"30046729243983873","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u9e97\u3057\u3044\u3002\u201c@omasanori: \u300c\u3082\u3046\u4f55\u5e74\u3082Haskell\u306e\u3053\u3068\u3057\u304b\u8003\u3048\u3066\u306a\u304b\u3063\u305f\u304b\u3089\u306a\u3001\u30eb\u30fc\u30d7\u306e\u4f7f\u3044\u65b9\u5fd8\u308c\u3066\u305f\u300d\u201d","id":30046729243983873,"from_user_id":5886055,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://itunes.apple.com/app/twitter/id333903271?mt=8&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPad&lt;/a&gt;"},{"from_user_id_str":"52620546","profile_image_url":"http://a1.twimg.com/profile_images/434693356/twitter-icon_normal.png","created_at":"Tue, 25 Jan 2011 23:36:26 +0000","from_user":"omasanori","id_str":"30046367187476481","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u300c\u3082\u3046\u4f55\u5e74\u3082Haskell\u306e\u3053\u3068\u3057\u304b\u8003\u3048\u3066\u306a\u304b\u3063\u305f\u304b\u3089\u306a\u3001\u30eb\u30fc\u30d7\u306e\u4f7f\u3044\u65b9\u5fd8\u308c\u3066\u305f\u300d","id":30046367187476481,"from_user_id":52620546,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.movatwi.jp&quot; rel=&quot;nofollow&quot;&gt;www.movatwi.jp&lt;/a&gt;"},{"from_user_id_str":"1659992","profile_image_url":"http://a1.twimg.com/profile_images/504488750/1_normal.jpg","created_at":"Tue, 25 Jan 2011 23:16:13 +0000","from_user":"finalfusion","id_str":"30041278544609280","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @necocen: Haskell\u306e\u30df\u30b5\u30ef\u3001\u3068\u3044\u3046\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u3066\u3071\u3063\u3068\u3057\u306a\u3044","id":30041278544609280,"from_user_id":1659992,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"272513","profile_image_url":"http://a2.twimg.com/profile_images/320244078/Mike_Painting2_normal.png","created_at":"Tue, 25 Jan 2011 23:05:09 +0000","from_user":"mikehadlow","id_str":"30038492373319680","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Just written the same simple program in C#, F# and Haskell: 18, 12 and 9 LoC respectively. And I'm much better at C# than F# or Haskell.","id":30038492373319680,"from_user_id":272513,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"89393264","profile_image_url":"http://a0.twimg.com/profile_images/1169486472/020_portland_me_normal.jpg","created_at":"Tue, 25 Jan 2011 23:01:28 +0000","from_user":"newsportlandme","id_str":"30037564589084673","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Governor's Choice to Run Maine DOC Under Scrutiny - MPBN: State Rep. Anne Haskell, a Portland Democrat, says Mai... http://bit.ly/fO30gC","id":30037564589084673,"from_user_id":89393264,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"38138","profile_image_url":"http://a3.twimg.com/profile_images/1212565885/Screen_shot_2011-01-11_at_5.28.47_PM_normal.png","created_at":"Tue, 25 Jan 2011 22:59:55 +0000","from_user":"michaelneale","id_str":"30037174615281664","metadata":{"result_type":"recent"},"to_user_id":null,"text":"The haskell EvilMangler http://t.co/P2Tls7J","id":30037174615281664,"from_user_id":38138,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"45692","profile_image_url":"http://a3.twimg.com/profile_images/1177741507/dogkarno_r_normal.jpg","created_at":"Tue, 25 Jan 2011 22:45:06 +0000","from_user":"karno","id_str":"30033448286552064","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u3063\u3066\u95a2\u6570\u306b\u30ab\u30ec\u30fc\u7c89\u3076\u3061\u8fbc\u3080\u3068\u304b\u306a\u3093\u3068\u304b","id":30033448286552064,"from_user_id":45692,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://yubitter.com/&quot; rel=&quot;nofollow&quot;&gt;yubitter&lt;/a&gt;"},{"from_user_id_str":"27605","profile_image_url":"http://a2.twimg.com/profile_images/15826632/meron_normal.jpg","created_at":"Tue, 25 Jan 2011 22:44:23 +0000","from_user":"celeron1ghz","id_str":"30033268761956352","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @necocen: Haskell\u306e\u30df\u30b5\u30ef\u3001\u3068\u3044\u3046\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u3066\u3071\u3063\u3068\u3057\u306a\u3044","id":30033268761956352,"from_user_id":27605,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"12901","profile_image_url":"http://a1.twimg.com/profile_images/56091349/haruhi_nagato-Y_normal.jpg","created_at":"Tue, 25 Jan 2011 22:43:30 +0000","from_user":"necocen","id_str":"30033044035346432","metadata":{"result_type":"recent"},"to_user_id":null,"text":"\u307e\u3042Haskell\u77e5\u3089\u3093\u3057\u306d","id":30033044035346432,"from_user_id":12901,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"12901","profile_image_url":"http://a1.twimg.com/profile_images/56091349/haruhi_nagato-Y_normal.jpg","created_at":"Tue, 25 Jan 2011 22:42:54 +0000","from_user":"necocen","id_str":"30032894856531968","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u306e\u30df\u30b5\u30ef\u3001\u3068\u3044\u3046\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u3066\u3071\u3063\u3068\u3057\u306a\u3044","id":30032894856531968,"from_user_id":12901,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"10821270","profile_image_url":"http://a0.twimg.com/profile_images/1195474259/Salto_Marlon_normal.jpg","created_at":"Tue, 25 Jan 2011 22:35:09 +0000","from_user":"jjedMoriAnktah","id_str":"30030942106025984","metadata":{"result_type":"recent"},"to_user_id":null,"text":"&quot;A Haskell program that outputs a Python program that outputs a Ruby program that outputs the original Haskell program&quot; http://is.gd/E6Julu","id":30030942106025984,"from_user_id":10821270,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"7554762","profile_image_url":"http://a0.twimg.com/profile_images/100515212/ajay-photo_normal.jpg","created_at":"Tue, 25 Jan 2011 22:34:30 +0000","from_user":"comatose_kid","id_str":"30030780205899776","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @bumptech: Bump Dev Blog - Why we use Haskell at Bump http://devblog.bu.mp/haskell-at-bump","id":30030780205899776,"from_user_id":7554762,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"148474705","profile_image_url":"http://a0.twimg.com/profile_images/1119234716/fur_hat_-_gilbeys_vodka_-_life_-_11-30-1962_normal.JPG","created_at":"Tue, 25 Jan 2011 22:29:19 +0000","from_user":"landmvintage","id_str":"30029476003840000","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @faerymoongodess: Magnificent Miriam Haskell Baroque Pearl Necklace by @MercyMadge http://etsy.me/hqRl51","id":30029476003840000,"from_user_id":148474705,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"37715508","profile_image_url":"http://a1.twimg.com/profile_images/1207891411/ballerina_normal.jpg","created_at":"Tue, 25 Jan 2011 22:24:52 +0000","from_user":"faerymoongodess","id_str":"30028356326002688","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Magnificent Miriam Haskell Baroque Pearl Necklace by @MercyMadge http://etsy.me/hqRl51","id":30028356326002688,"from_user_id":37715508,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Tue, 25 Jan 2011 22:17:16 +0000","from_user":"Hackage","id_str":"30026442456694784","metadata":{"result_type":"recent"},"to_user_id":null,"text":"base16-bytestring 0.1.0.0, added by BryanOSullivan: Fast base16 (hex) encoding and deconding for ByteStrings http://bit.ly/eu75TN","id":30026442456694784,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"199750997","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Tue, 25 Jan 2011 22:12:07 +0000","from_user":"benreads","id_str":"30025146991382528","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Writing Systems Software in a Functional Language -- brief, but fun. I want to see how well they can make Systems Haskell perform at scale.","id":30025146991382528,"from_user_id":199750997,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"35359797","profile_image_url":"http://a1.twimg.com/profile_images/1173453785/48893_521140819_1896062_q_normal.jpg","created_at":"Tue, 25 Jan 2011 22:09:45 +0000","from_user":"jcawthorne1","id_str":"30024549265309696","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Just saw Jeff Haskell give the middle finger!! Lol awesome","id":30024549265309696,"from_user_id":35359797,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Tue, 25 Jan 2011 22:06:44 +0000","from_user":"goodfox","id_str":"30023790381498369","metadata":{"result_type":"recent"},"to_user_id":null,"text":"At the Haskell Convocation. (@ Haskell Indian Nations U Auditorium) http://4sq.com/eKKXyn","id":30023790381498369,"from_user_id":13540930,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://foursquare.com&quot; rel=&quot;nofollow&quot;&gt;foursquare&lt;/a&gt;"},{"from_user_id_str":"14674418","profile_image_url":"http://a2.twimg.com/profile_images/238230125/IMG_1030-1_normal.jpg","created_at":"Tue, 25 Jan 2011 22:02:31 +0000","from_user":"sanityinc","id_str":"30022731919523840","metadata":{"result_type":"recent"},"to_user_id":371289,"text":"@xshay Haskell's great, but Clojure's similarly lazy in all the ways that matter, and is more practical for day-to-day use.","id":30022731919523840,"from_user_id":14674418,"to_user":"xshay","geo":null,"iso_language_code":"en","to_user_id_str":"371289","source":"&lt;a href=&quot;http://www.echofon.com/&quot; rel=&quot;nofollow&quot;&gt;Echofon&lt;/a&gt;"},{"from_user_id_str":"371289","profile_image_url":"http://a2.twimg.com/profile_images/1113482439/me-brisbane_normal.jpg","created_at":"Tue, 25 Jan 2011 21:58:29 +0000","from_user":"xshay","id_str":"30021714444292096","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Just made a lazy sequence of prime numbers in haskell. I'm smitten.","id":30021714444292096,"from_user_id":371289,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"199453873","profile_image_url":"http://a3.twimg.com/a/1294785484/images/default_profile_3_normal.png","created_at":"Tue, 25 Jan 2011 21:48:40 +0000","from_user":"stackfeed","id_str":"30019243982454784","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Practical Scala reference manual, for searching things like method names: Hello, \n\nInspired by\nHaskell API Searc... http://bit.ly/g4zWZQ","id":30019243982454784,"from_user_id":199453873,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Tue, 25 Jan 2011 21:45:32 +0000","from_user":"aapnoot","id_str":"30018455189065728","metadata":{"result_type":"recent"},"to_user_id":null,"text":"download 0.3.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/i8mYvi","id":30018455189065728,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Tue, 25 Jan 2011 21:45:31 +0000","from_user":"aapnoot","id_str":"30018452601180160","metadata":{"result_type":"recent"},"to_user_id":null,"text":"download 0.3.1.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/eHfiJB","id":30018452601180160,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Tue, 25 Jan 2011 21:45:31 +0000","from_user":"Hackage","id_str":"30018451867176960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"download 0.3.1, added by MagnusTherning: High-level file download based on URLs http://bit.ly/i8mYvi","id":30018451867176960,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"138502705","profile_image_url":"http://a1.twimg.com/profile_images/1083845614/yclogo_normal.gif","created_at":"Tue, 25 Jan 2011 21:45:04 +0000","from_user":"newsyc100","id_str":"30018340839755777","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell improves log processing 4x over Python http://devblog.bu.mp/haskell-at-bump (http://bit.ly/gQxxR8)","id":30018340839755777,"from_user_id":138502705,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://news.ycombinator.com&quot; rel=&quot;nofollow&quot;&gt;newsyc&lt;/a&gt;"},{"from_user_id_str":"1578246","profile_image_url":"http://a0.twimg.com/profile_images/59312315/avatar_simpson_small_normal.jpg","created_at":"Tue, 25 Jan 2011 21:43:32 +0000","from_user":"magthe","id_str":"30017953801969665","metadata":{"result_type":"recent"},"to_user_id":null,"text":"New version of download uploaded to #hackage #haskell","id":30017953801969665,"from_user_id":1578246,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://api.supertweet.net&quot; rel=&quot;nofollow&quot;&gt;MyAuth API Proxy&lt;/a&gt;"},{"from_user_id_str":"135838970","profile_image_url":"http://a2.twimg.com/profile_images/1079929891/logo_normal.png","created_at":"Tue, 25 Jan 2011 21:37:51 +0000","from_user":"reward999","id_str":"30016525180084224","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Found Great Dane (Main &amp; Haskell- Dallas): We found a great dane. 214-712-0000 http://bit.ly/fQ8iBw","id":30016525180084224,"from_user_id":135838970,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"137719265","profile_image_url":"http://a2.twimg.com/profile_images/1092224079/8__4__normal.jpg","created_at":"Tue, 25 Jan 2011 21:34:22 +0000","from_user":"WeiMatas","id_str":"30015646020411392","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Fourth day Rez party Eddie Haskell County in second life \u2013 which took place in cabaret Tadd","id":30015646020411392,"from_user_id":137719265,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://dlvr.it&quot; rel=&quot;nofollow&quot;&gt;dlvr.it&lt;/a&gt;"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Tue, 25 Jan 2011 21:33:21 +0000","from_user":"listwarenet","id_str":"30015392571195392","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/83889-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Haskell-cafe -","id":30015392571195392,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://1e10.org/cloud/&quot; rel=&quot;nofollow&quot;&gt;1e10&lt;/a&gt;"}],"max_id":30121530767708160,"since_id":0,"refresh_url":"?since_id=30121530767708160&q=haskell","next_page":"?page=2&max_id=30121530767708160&rpp=100&q=haskell","results_per_page":100,"page":1,"completed_in":1.195569,"since_id_str":"0","max_id_str":"30121530767708160","query":"haskell"}
+ test/json-data/twitter20.json view
@@ -0,0 +1,1 @@+{"results":[{"from_user_id_str":"166199691","profile_image_url":"http://a2.twimg.com/profile_images/1252958188/38_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"_classicc","id_str":"41191052790603776","metadata":{"result_type":"recent"},"to_user_id":null,"text":"my twitter is actin slow today.","id":41191052790603776,"from_user_id":166199691,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"138835410","profile_image_url":"http://a1.twimg.com/profile_images/1250985094/243321801_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"amereronday","id_str":"41191050307567616","metadata":{"result_type":"recent"},"to_user_id":null,"text":"twitter jail, here i come.","id":41191050307567616,"from_user_id":138835410,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"359548","profile_image_url":"http://a2.twimg.com/profile_images/53612334/don_otvos_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"donnyo","id_str":"41191050110451712","metadata":{"result_type":"recent"},"to_user_id":7074534,"text":"@stlsmallbiz I see there is currently a Twitter promo too....tempting....","id":41191050110451712,"from_user_id":359548,"to_user":"stlsmallbiz","geo":null,"iso_language_code":"en","place":{"id":"82b7b2f97b12261d","type_":"poi","full_name":"Yammer Inc, San Francisco"},"to_user_id_str":"7074534","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"122523770","profile_image_url":"http://a0.twimg.com/profile_images/1073533262/11646_1076222405045_1810798478_156114_3663737_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:26 +0000","from_user":"msBreChan","id_str":"41191049720238080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"so twitter gt spam now -_-","id":41191049720238080,"from_user_id":122523770,"geo":{"type_":"Point","coordinates":[35.2213,-80.8276]},"iso_language_code":"en","place":{"id":"4d5ed95f830e9b41","type_":"neighborhood","full_name":"Elizabeth, Charlotte"},"to_user_id_str":null,"source":"&lt;a href=&quot;http://mobile.twitter.com&quot; rel=&quot;nofollow&quot;&gt;Twitter for Android&lt;/a&gt;"},{"from_user_id_str":"229024950","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_6_normal.png","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"NinaMaechik","id_str":"41191047853912064","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Glad I can remember my twitter password!  LOL!  Hugs to Nick from his aunties...","id":41191047853912064,"from_user_id":229024950,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"215545822","profile_image_url":"http://a2.twimg.com/profile_images/1239909540/RTL_normal.png","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"RightToLaugh","id_str":"41191047371558912","metadata":{"result_type":"recent"},"to_user_id":null,"text":"#Bacon wrapped dates http://bit.ly/hUxVC9 Just like my grandma used to make http://twitter.com/#","id":41191047371558912,"from_user_id":215545822,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"217845526","profile_image_url":"http://a0.twimg.com/sticky/default_profile_images/default_profile_3_normal.png","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"TheShoeLooker","id_str":"41191047052804096","metadata":{"result_type":"recent"},"to_user_id":38033240,"text":"@ShoeDazzle love love love to twitter or blog about your deals and shoes!\ntheshoelooker.blogspot.com","id":41191047052804096,"from_user_id":217845526,"to_user":"shoedazzle","geo":null,"iso_language_code":"en","to_user_id_str":"38033240","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"24953438","profile_image_url":"http://a3.twimg.com/profile_images/1181252763/76820_10150100014748783_677998782_7386695_4377006_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"liljermaine32","id_str":"41191046025056256","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Twitter fam I gotta question 4 ya is texas south or midwest #arguments","id":41191046025056256,"from_user_id":24953438,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://mobile.twitter.com&quot; rel=&quot;nofollow&quot;&gt;Twitter for Android&lt;/a&gt;"},{"from_user_id_str":"122451024","profile_image_url":"http://a2.twimg.com/profile_images/1143400129/100706-ETCanada_201134_1__normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:25 +0000","from_user":"Kim_DEon","id_str":"41191045161164801","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Help @CARE @EvaLongoria and ME use Twitter to change the lives of girls in poverty across the world! Ready? Go to http://TwitChange.com NOW!","id":41191045161164801,"from_user_id":122451024,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"128351479","profile_image_url":"http://a3.twimg.com/profile_images/1150198829/Kirby_Photo__edit__normal.JPG","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"TheDaveKirby","id_str":"41191043894493184","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Maybe its time to clean house...MY HOUSE http://bit.ly/ejG22P","id":41191043894493184,"from_user_id":128351479,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"87512773","profile_image_url":"http://a0.twimg.com/profile_images/1252511106/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"supportthehood","id_str":"41191043206610946","metadata":{"result_type":"recent"},"to_user_id":2467330,"text":"@eastcoastmp3 #FF  it's the way twitter works !!!","id":41191043206610946,"from_user_id":87512773,"to_user":"eastcoastmp3","geo":null,"iso_language_code":"en","to_user_id_str":"2467330","source":"&lt;a href=&quot;http://twitter.com/&quot; rel=&quot;nofollow&quot;&gt;Twitter for iPhone&lt;/a&gt;"},{"from_user_id_str":"149894545","profile_image_url":"http://a0.twimg.com/profile_images/1219334400/patrick_camo_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"suburbpat","id_str":"41191040912330752","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I havent had a rib session on twitter in a while.......I wanna Rib with a nigga with alot followers lol","id":41191040912330752,"from_user_id":149894545,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"97749622","profile_image_url":"http://a0.twimg.com/profile_images/1254640781/IMG1633A_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:24 +0000","from_user":"jrricardosantos","id_str":"41191040547430400","metadata":{"result_type":"recent"},"to_user_id":101017476,"text":"@yofzs pq tirou o CAPS LOCK? kkkk tava bem legal...hehehe eu estou no t\u00e9dio...kkk tbm estou no twitter e msn..aff!!","id":41191040547430400,"from_user_id":97749622,"to_user":"yofzs","geo":null,"iso_language_code":"en","to_user_id_str":"101017476","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"94381536","profile_image_url":"http://a1.twimg.com/profile_images/1174777929/41509_100001699300415_3521888_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"DonNieves","id_str":"41191038978752512","metadata":{"result_type":"recent"},"to_user_id":151926400,"text":"@TiiH13 cheira meu ovo, no email, no orkut, no msn, no facebook, no twitter, no skype, no spark, no ICQ e no google talk","id":41191038978752512,"from_user_id":94381536,"to_user":"TiiH13","geo":null,"iso_language_code":"en","to_user_id_str":"151926400","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"211858432","profile_image_url":"http://a3.twimg.com/profile_images/1231906180/JonasBrothers_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"OriginalJBfans","id_str":"41191038328651776","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I literally forgot about this twitter... so whats occuring followers?","id":41191038328651776,"from_user_id":211858432,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"90317132","profile_image_url":"http://a3.twimg.com/profile_images/1230085056/254101635_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"Just2smooth","id_str":"41191036936126464","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Wassup twitter","id":41191036936126464,"from_user_id":90317132,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://ubersocial.com&quot; rel=&quot;nofollow&quot;&gt;\u00dcberSocial&lt;/a&gt;"},{"from_user_id_str":"144771504","profile_image_url":"http://a1.twimg.com/profile_images/1243343836/image_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:23 +0000","from_user":"ima_b_b_badman","id_str":"41191036638339072","metadata":{"result_type":"recent"},"to_user_id":null,"text":"i been M.I.A. all day twitter my bad","id":41191036638339072,"from_user_id":144771504,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"207922664","profile_image_url":"http://a2.twimg.com/profile_images/1237106108/258356167_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:22 +0000","from_user":"itsthecarter_","id_str":"41191036013391873","metadata":{"result_type":"recent"},"to_user_id":null,"text":"twitter is a stupid addiction.","id":41191036013391873,"from_user_id":207922664,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://ubersocial.com&quot; rel=&quot;nofollow&quot;&gt;\u00dcberSocial&lt;/a&gt;"},{"from_user_id_str":"150000649","profile_image_url":"http://a0.twimg.com/profile_images/1237789059/belllaa_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:22 +0000","from_user":"angelicabrvo","id_str":"41191035707207680","metadata":{"result_type":"recent"},"to_user_id":null,"text":"que hubo twitter? huy que feoxd","id":41191035707207680,"from_user_id":150000649,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://blackberry.com/twitter&quot; rel=&quot;nofollow&quot;&gt;Twitter for BlackBerry\u00ae&lt;/a&gt;"},{"from_user_id_str":"185713003","profile_image_url":"http://a2.twimg.com/profile_images/1191421540/163229_177015295661467_154687431227587_492170_2147500_n_normal.jpg","created_at":"Fri, 25 Feb 2011 17:41:22 +0000","from_user":"downbytheshores","id_str":"41191033945595905","metadata":{"result_type":"recent"},"to_user_id":null,"text":"follow us on twitter\nwww.twitter.com/downbytheshores http://fb.me/DhDS915e","id":41191033945595905,"from_user_id":185713003,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.facebook.com/twitter&quot; rel=&quot;nofollow&quot;&gt;Facebook&lt;/a&gt;"}],"max_id":41191052790603776,"since_id":38643906774044672,"refresh_url":"?since_id=41191052790603776&q=twitter","next_page":"?page=2&max_id=41191052790603776&rpp=20&lang=en&q=twitter","results_per_page":20,"page":1,"completed_in":0.128719,"warning":"adjusted since_id to 38643906774044672 (), requested since_id was older than allowed -- since_id removed for pagination.","since_id_str":"38643906774044672","max_id_str":"41191052790603776","query":"twitter"}
+ test/json-data/twitter50.json view
@@ -0,0 +1,1 @@+{"results":[{"from_user_id_str":"207858021","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 04:30:38 +0000","from_user":"pboudarga","id_str":"30120402839666689","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Rolla Sushi Grill (27737 Bouquet Canyon Road, #106, Btw Haskell Canyon and Rosedell Drive, Saugus) http://4sq.com/gqqdhs","id":30120402839666689,"from_user_id":207858021,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://foursquare.com&quot; rel=&quot;nofollow&quot;&gt;foursquare&lt;/a&gt;"},{"from_user_id_str":"69988683","profile_image_url":"http://a0.twimg.com/profile_images/1211955817/avatar_7888_normal.gif","created_at":"Wed, 26 Jan 2011 04:25:23 +0000","from_user":"YNK33","id_str":"30119083059978240","metadata":{"result_type":"recent"},"to_user_id":null,"text":"hsndfile 0.5.0: Free and open source Haskell bindings for libsndfile http://bit.ly/gHaBWG Mac Os","id":30119083059978240,"from_user_id":69988683,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"81492","profile_image_url":"http://a1.twimg.com/profile_images/423894208/Picture_7_normal.jpg","created_at":"Wed, 26 Jan 2011 04:24:28 +0000","from_user":"satzz","id_str":"30118851488251904","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Emacs\u306e\u30e2\u30fc\u30c9\u8868\u793a\u304c\u4eca(Ruby Controller Outputz RoR Flymake REl hs)\u3068\u306a\u3063\u3066\u3066\u3088\u304f\u308f\u304b\u3089\u306a\u3044\u3093\u3060\u3051\u3069\u6700\u5f8c\u306eREl\u3068\u304bhs\u3063\u3066\u4f55\u3060\u308d\u3046\u2026haskell\u3068\u304b2\u5e74\u4ee5\u4e0a\u66f8\u3044\u3066\u306a\u3044\u3051\u3069\u2026","id":30118851488251904,"from_user_id":81492,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.hootsuite.com&quot; rel=&quot;nofollow&quot;&gt;HootSuite&lt;/a&gt;"},{"from_user_id_str":"9518356","profile_image_url":"http://a2.twimg.com/profile_images/119165723/ocaml-icon_normal.png","created_at":"Wed, 26 Jan 2011 04:19:19 +0000","from_user":"planet_ocaml","id_str":"30117557788741632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I so miss #haskell type classes in #ocaml - i want to do something like refinement. Also why does ocaml not have... http://bit.ly/geYRwt","id":30117557788741632,"from_user_id":9518356,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"218059","profile_image_url":"http://a1.twimg.com/profile_images/1053837723/twitter-icon9_normal.jpg","created_at":"Wed, 26 Jan 2011 04:16:32 +0000","from_user":"aprikip","id_str":"30116854940835840","metadata":{"result_type":"recent"},"to_user_id":null,"text":"yatex-mode\u3084haskell-mode\u306e\u3053\u3068\u3067\u3059\u306d\u3001\u308f\u304b\u308a\u307e\u3059\u3002","id":30116854940835840,"from_user_id":218059,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://sites.google.com/site/yorufukurou/&quot; rel=&quot;nofollow&quot;&gt;YoruFukurou&lt;/a&gt;"},{"from_user_id_str":"216363","profile_image_url":"http://a1.twimg.com/profile_images/72454310/Tim-Avatar_normal.png","created_at":"Wed, 26 Jan 2011 04:15:30 +0000","from_user":"dysinger","id_str":"30116594684264448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell in Hawaii tonight for me... #fun","id":30116594684264448,"from_user_id":216363,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.nambu.com/&quot; rel=&quot;nofollow&quot;&gt;Nambu&lt;/a&gt;"},{"from_user_id_str":"1774820","profile_image_url":"http://a2.twimg.com/profile_images/61169291/dan_desert_thumb_normal.jpg","created_at":"Wed, 26 Jan 2011 04:13:36 +0000","from_user":"DanMil","id_str":"30116117682851840","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire @tomheon Haskell isn't a language, it's a belief system.  A seductive one...","id":30116117682851840,"from_user_id":1774820,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"659256","profile_image_url":"http://a0.twimg.com/profile_images/746976711/angular-final_normal.jpg","created_at":"Wed, 26 Jan 2011 04:11:06 +0000","from_user":"djspiewak","id_str":"30115488931520512","metadata":{"result_type":"recent"},"to_user_id":null,"text":"One of the very nice things about Haskell as opposed to SML is the reduced proliferation of identifiers (e.g. andb, orb, etc). #typeclasses","id":30115488931520512,"from_user_id":659256,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 04:06:12 +0000","from_user":"listwarenet","id_str":"30114255890026496","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-cafe/84752-re-haskell-cafe-gpl-license-of-h-matrix-and-prelude-numeric.html Re: Haskell-c","id":30114255890026496,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://1e10.org/cloud/&quot; rel=&quot;nofollow&quot;&gt;1e10&lt;/a&gt;"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 04:01:29 +0000","from_user":"ojrac","id_str":"30113067333324800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @tomheon: @ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30113067333324800,"from_user_id":1594784,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"207589736","profile_image_url":"http://a3.twimg.com/profile_images/1225527428/headshot_1_normal.jpg","created_at":"Wed, 26 Jan 2011 04:00:13 +0000","from_user":"ashleevelazq101","id_str":"30112747555397632","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/dONnpn","id":30112747555397632,"from_user_id":207589736,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"Hackage","id_str":"30112192346984448","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112192346984448,"from_user_id":17671137,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"17489366","profile_image_url":"http://a3.twimg.com/sticky/default_profile_images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 03:58:00 +0000","from_user":"aapnoot","id_str":"30112191881420800","metadata":{"result_type":"recent"},"to_user_id":null,"text":"streams 0.4, added by EdwardKmett: Various Haskell 2010 stream comonads http://bit.ly/idBkPe","id":30112191881420800,"from_user_id":17489366,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"8530482","profile_image_url":"http://a2.twimg.com/profile_images/137867266/n608671563_7396_normal.jpg","created_at":"Wed, 26 Jan 2011 03:50:12 +0000","from_user":"jeffmclamb","id_str":"30110229207187456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Angel - daemon to run and monitor processes like daemontools or god, written in Haskell http://ff.im/-wNyLk","id":30110229207187456,"from_user_id":8530482,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://friendfeed.com&quot; rel=&quot;nofollow&quot;&gt;FriendFeed&lt;/a&gt;"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:46:01 +0000","from_user":"tomheon","id_str":"30109174645919744","metadata":{"result_type":"recent"},"to_user_id":1594784,"text":"@ojrac @chewedwire Don't worry, learning Haskell will not give you any clear idea what monad means.","id":30109174645919744,"from_user_id":177539201,"to_user":"ojrac","geo":null,"iso_language_code":"en","to_user_id_str":"1594784","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"1594784","profile_image_url":"http://a2.twimg.com/profile_images/378515773/square-profile_normal.jpg","created_at":"Wed, 26 Jan 2011 03:44:34 +0000","from_user":"ojrac","id_str":"30108808684503040","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire @tomheon Why are you making me curious about Haskell? I LIKE not knowing what monad means!!","id":30108808684503040,"from_user_id":1594784,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"23750094","profile_image_url":"http://a0.twimg.com/profile_images/951373780/Moeinthecar_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:54 +0000","from_user":"shokalshab","id_str":"30108140443795456","metadata":{"result_type":"recent"},"to_user_id":null,"text":"I'm at Magnitude Cheer @ Gymnastics Olympica USA (7735 Haskell Ave., btw Saticoy &amp; Strathern, Van Nuys) http://4sq.com/gmXfaL","id":30108140443795456,"from_user_id":23750094,"geo":null,"iso_language_code":"en","place":{"id":"4e4a2a2f86cb2946","type_":"poi","full_name":"Gymnastics Olympica USA, Van Nuys"},"to_user_id_str":null,"source":"&lt;a href=&quot;http://foursquare.com&quot; rel=&quot;nofollow&quot;&gt;foursquare&lt;/a&gt;"},{"from_user_id_str":"8135112","profile_image_url":"http://a0.twimg.com/profile_images/1165240350/LIMITED_normal.jpg","created_at":"Wed, 26 Jan 2011 03:41:35 +0000","from_user":"Claricei","id_str":"30108059208515584","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @kristenmchugh22: @KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30108059208515584,"from_user_id":8135112,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:40:02 +0000","from_user":"chewedwire","id_str":"30107670367182848","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon Cool, I'll take a look. I feel like I should mention this: http://bit.ly/hVstDM","id":30107670367182848,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"8679778","profile_image_url":"http://a3.twimg.com/profile_images/1195318056/me_nyc_12_18_10_icon_normal.jpg","created_at":"Wed, 26 Jan 2011 03:38:42 +0000","from_user":"kristenmchugh22","id_str":"30107332381777920","metadata":{"result_type":"recent"},"to_user_id":756269,"text":"@KeithOlbermann Ryan looks like Jughead w/o the hat. And sounds as mealy-mouthed as Eddie Haskell.","id":30107332381777920,"from_user_id":8679778,"to_user":"KeithOlbermann","geo":null,"iso_language_code":"en","to_user_id_str":"756269","source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"103316559","profile_image_url":"http://a1.twimg.com/profile_images/1179458751/bc3beab4-d59d-4e78-b13b-50747986cfa2_normal.png","created_at":"Wed, 26 Jan 2011 03:36:15 +0000","from_user":"cityslikr","id_str":"30106719153557504","metadata":{"result_type":"recent"},"to_user_id":null,"text":"&quot;Social safety net into a hammock.&quot; So says Eddie Haskell with the GOP response. #SOTU","id":30106719153557504,"from_user_id":103316559,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://blackberry.com/twitter&quot; rel=&quot;nofollow&quot;&gt;Twitter for BlackBerry\u00ae&lt;/a&gt;"},{"from_user_id_str":"169063143","profile_image_url":"http://a0.twimg.com/profile_images/1160506212/9697_1_normal.gif","created_at":"Wed, 26 Jan 2011 03:31:52 +0000","from_user":"wrkforce_safety","id_str":"30105614919143424","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Federal investigation finds safety violations at The Acadia Hospital: By Meg Haskell, BDN Staff The investigatio... http://bit.ly/gA60C1","id":30105614919143424,"from_user_id":169063143,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 03:29:40 +0000","from_user":"tomheon","id_str":"30105060960632832","metadata":{"result_type":"recent"},"to_user_id":128028225,"text":"@chewedwire Great book on Haskell: http://oreilly.com/catalog/9780596514983","id":30105060960632832,"from_user_id":177539201,"to_user":"chewedwire","geo":null,"iso_language_code":"en","to_user_id_str":"128028225","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"782692","profile_image_url":"http://a0.twimg.com/profile_images/1031304589/Profile.2007.1_normal.jpg","created_at":"Wed, 26 Jan 2011 03:29:19 +0000","from_user":"turnageb","id_str":"30104974591533057","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @ovillalon: Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104974591533057,"from_user_id":782692,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:28:04 +0000","from_user":"chewedwire","id_str":"30104657267265536","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon I always loved the pattern matching in SML and it looks like Haskell is MUCH better at it. I'm messing around now at tryhaskell.org","id":30104657267265536,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"12834082","profile_image_url":"http://a3.twimg.com/profile_images/1083036140/mugshot_normal.png","created_at":"Wed, 26 Jan 2011 03:28:01 +0000","from_user":"ovillalon","id_str":"30104647213518848","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Paul Ryan solves the mystery of whatever happened to Eddie Haskell. #sotu","id":30104647213518848,"from_user_id":12834082,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:26:02 +0000","from_user":"goodfox","id_str":"30104146455560192","metadata":{"result_type":"recent"},"to_user_id":10226179,"text":"@billykeene22 Bordeaux is one of my heroes. I was so excited when he accepted the invitation to campus. He's been a great friend to Haskell.","id":30104146455560192,"from_user_id":13540930,"to_user":"billykeene22","geo":null,"iso_language_code":"en","to_user_id_str":"10226179","source":"&lt;a href=&quot;http://www.ubertwitter.com/bb/download.php&quot; rel=&quot;nofollow&quot;&gt;\u00dcberTwitter&lt;/a&gt;"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 03:25:18 +0000","from_user":"josej30","id_str":"30103962313031681","metadata":{"result_type":"recent"},"to_user_id":14870909,"text":"@cris7ian Ahh bueno multiparadigma ya es respetable :) Empezar\u00e9 a explotar la parte funcional de los lenguajes ahora #Haskell","id":30103962313031681,"from_user_id":18616016,"to_user":"Cris7ian","geo":null,"iso_language_code":"es","to_user_id_str":"14870909","source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"14870909","profile_image_url":"http://a2.twimg.com/profile_images/1176930429/oso_yo_normal.png","created_at":"Wed, 26 Jan 2011 03:23:43 +0000","from_user":"Cris7ian","id_str":"30103562360983553","metadata":{"result_type":"recent"},"to_user_id":18616016,"text":"@josej30 hahaha no, es multiparadigma y es bastante lazy. Nothing like haskell, pero s\u00ed, el de Flash","id":30103562360983553,"from_user_id":14870909,"to_user":"josej30","geo":null,"iso_language_code":"es","to_user_id_str":"18616016","source":"&lt;a href=&quot;http://www.echofon.com/&quot; rel=&quot;nofollow&quot;&gt;Echofon&lt;/a&gt;"},{"from_user_id_str":"2421643","profile_image_url":"http://a0.twimg.com/profile_images/1190361665/ernestgrumbles-17_normal.jpg","created_at":"Wed, 26 Jan 2011 03:20:24 +0000","from_user":"ernestgrumbles","id_str":"30102730756333568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Wow... WolframAlpha did not know who Eddie Haskell is.  Guess I'll never use that &quot;knowledge engine&quot; again.","id":30102730756333568,"from_user_id":2421643,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"128028225","profile_image_url":"http://a1.twimg.com/profile_images/1224994593/Coding_Drunk_normal.jpg","created_at":"Wed, 26 Jan 2011 03:14:21 +0000","from_user":"chewedwire","id_str":"30101204428132352","metadata":{"result_type":"recent"},"to_user_id":177539201,"text":"@tomheon How is Haskell better/different from CL or Scheme? I honestly don't know, although I'm becoming more curious.","id":30101204428132352,"from_user_id":128028225,"to_user":"tomheon","geo":null,"iso_language_code":"en","to_user_id_str":"177539201","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"13540930","profile_image_url":"http://a1.twimg.com/profile_images/1205312219/23467_350321383101_821143101_5114147_3010041_n_normal.jpg","created_at":"Wed, 26 Jan 2011 03:06:54 +0000","from_user":"goodfox","id_str":"30099329809129473","metadata":{"result_type":"recent"},"to_user_id":null,"text":"A day of vision &amp; speeches. #SOTU now. And a wonderful Haskell Convocation address earlier today by Sinte Gleske President Lionel Bordeaux.","id":30099329809129473,"from_user_id":13540930,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.ubertwitter.com/bb/download.php&quot; rel=&quot;nofollow&quot;&gt;\u00dcberTwitter&lt;/a&gt;"},{"from_user_id_str":"119185220","profile_image_url":"http://a0.twimg.com/profile_images/1089027228/dfg_normal.jpg","created_at":"Wed, 26 Jan 2011 03:03:38 +0000","from_user":"LaLiciouz_03","id_str":"30098510623805440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"The Game with the girl room 330 Haskell follow us...","id":30098510623805440,"from_user_id":119185220,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"18616016","profile_image_url":"http://a2.twimg.com/profile_images/1173522726/214397343_normal.jpg","created_at":"Wed, 26 Jan 2011 02:57:25 +0000","from_user":"josej30","id_str":"30096946144215040","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Voy a extra\u00f1ar Haskell cuando regrese al mundo imperativo. Hay alg\u00fan lenguaje imperativo que tenga este poder funcional? #ci3661","id":30096946144215040,"from_user_id":18616016,"geo":null,"iso_language_code":"es","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"17671137","profile_image_url":"http://a2.twimg.com/profile_images/290264834/Haskell-logo-outer-glow_normal.png","created_at":"Wed, 26 Jan 2011 02:55:32 +0000","from_user":"Hackage","id_str":"30096471814574080","metadata":{"result_type":"recent"},"to_user_id":null,"text":"comonad-transformers 0.9.0, added by EdwardKmett: Haskell 98 comonad transformers http://bit.ly/h6xIsf","id":30096471814574080,"from_user_id":17671137,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitterfeed.com&quot; rel=&quot;nofollow&quot;&gt;twitterfeed&lt;/a&gt;"},{"from_user_id_str":"177539201","profile_image_url":"http://a0.twimg.com/profile_images/1178368800/img_normal.jpeg","created_at":"Wed, 26 Jan 2011 02:48:12 +0000","from_user":"tomheon","id_str":"30094626920603649","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Every time I look at Haskell I love it more.","id":30094626920603649,"from_user_id":177539201,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"60792568","profile_image_url":"http://a0.twimg.com/profile_images/1203647517/glenda-flash_normal.jpg","created_at":"Wed, 26 Jan 2011 02:40:42 +0000","from_user":"r_takaishi","id_str":"30092735935422464","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell\u3088\u308aD\u8a00\u8a9e\u304c\u4e0a\u3068\u306f\u601d\u308f\u306a\u304b\u3063\u305f\uff0e http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html","id":30092735935422464,"from_user_id":60792568,"geo":null,"iso_language_code":"ja","to_user_id_str":null,"source":"&lt;a href=&quot;http://twmode.sf.net/&quot; rel=&quot;nofollow&quot;&gt;twmode&lt;/a&gt;"},{"from_user_id_str":"160145510","profile_image_url":"http://a0.twimg.com/profile_images/1218108166/going_galt_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:31 +0000","from_user":"wtp1787","id_str":"30092439653974018","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @KLSouth: Eddie Haskell Goes to Washington...  &quot;You look really nice tonight, Ms Cleaver&quot;","id":30092439653974018,"from_user_id":160145510,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"96616016","profile_image_url":"http://a1.twimg.com/profile_images/1196978169/Picture0002_normal.jpg","created_at":"Wed, 26 Jan 2011 02:39:20 +0000","from_user":"MelissaRNMBA","id_str":"30092392203816960","metadata":{"result_type":"recent"},"to_user_id":14862975,"text":"@KLSouth At least Eddie Haskell was entertaining.","id":30092392203816960,"from_user_id":96616016,"to_user":"KLSouth","geo":null,"iso_language_code":"en","to_user_id_str":"14862975","source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"14862975","profile_image_url":"http://a0.twimg.com/profile_images/421596393/kls_4_normal.JPG","created_at":"Wed, 26 Jan 2011 02:38:29 +0000","from_user":"KLSouth","id_str":"30092178327871489","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Eddie Haskell Goes to Washington...  &quot;You look really nice tonight, Ms Cleaver&quot;","id":30092178327871489,"from_user_id":14862975,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.tweetdeck.com&quot; rel=&quot;nofollow&quot;&gt;TweetDeck&lt;/a&gt;"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 02:36:17 +0000","from_user":"listwarenet","id_str":"30091626869161984","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84641-haskell-beginners-wildcards-in-expressions.html Haskell-beginners -  Wild","id":30091626869161984,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://1e10.org/cloud/&quot; rel=&quot;nofollow&quot;&gt;1e10&lt;/a&gt;"},{"from_user_id_str":"24538048","profile_image_url":"http://a2.twimg.com/profile_images/1117267605/rope_normal.jpg","created_at":"Wed, 26 Jan 2011 02:23:14 +0000","from_user":"dbph","id_str":"30088341030440960","metadata":{"result_type":"recent"},"to_user_id":null,"text":"RT @dnene: Skilled Calisthenics. Haskell code that outputs python which spits ruby which emits the haskell source. http://j.mp/YlQUL via @mfeathers","id":30088341030440960,"from_user_id":24538048,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:58:31 +0000","from_user":"YubaVetTech","id_str":"30082124207886336","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigious Hayward Award for \u2018Excellence in Education\u2019. This award honors... http://fb.me/QgQCxd74","id":30082124207886336,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.facebook.com/twitter&quot; rel=&quot;nofollow&quot;&gt;Facebook&lt;/a&gt;"},{"from_user_id_str":"158951567","profile_image_url":"http://a3.twimg.com/profile_images/962721419/Logo_3_normal.jpg","created_at":"Wed, 26 Jan 2011 01:56:04 +0000","from_user":"YubaVetTech","id_str":"30081505476743168","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Dr. Haskell has just been awarded the prestigous Haward Award for Excellence in Education. This award honors... http://fb.me/PC9mYmCR","id":30081505476743168,"from_user_id":158951567,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://www.facebook.com/twitter&quot; rel=&quot;nofollow&quot;&gt;Facebook&lt;/a&gt;"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:43:50 +0000","from_user":"Verus","id_str":"30078427155406848","metadata":{"result_type":"recent"},"to_user_id":79273052,"text":"@kami_joe \u3044\u3084\uff0c\u8ab2\u984c\u306f\u89e3\u6c7a\u5bfe\u8c61(\u30d1\u30ba\u30eb\u3068\u304b)\u3092\u4e0e\u3048\u3089\u308c\u3066\uff0c\u554f\u984c\u5b9a\u7fa9\u3068\u30d7\u30ed\u30b0\u30e9\u30df\u30f3\u30b0(\u6307\u5b9a\u8a00\u8a9e\u306fC++\u3082\u3057\u304f\u306fJava)\u3068\u3044\u3046\u3044\u308f\u3070\u666e\u901a\u306a\u8ab2\u984c\u3067\u306f\u3042\u308b\u3093\u3060\u3051\u3069\uff0e\u95a2\u6570\u578b\u8a00\u8a9e\u306fHaskell\u306e\u6388\u696d\u304c\u307e\u305f\u5225\u306b\u3042\u308b\u306e\uff0e","id":30078427155406848,"from_user_id":2331498,"to_user":"kami_joe","geo":null,"iso_language_code":"ja","to_user_id_str":"79273052","source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"79151233","profile_image_url":"http://a2.twimg.com/a/1295051201/images/default_profile_2_normal.png","created_at":"Wed, 26 Jan 2011 01:40:37 +0000","from_user":"cz_newdrafts","id_str":"30077617361125376","metadata":{"result_type":"recent"},"to_user_id":null,"text":"Haskell programming language http://bit.ly/gpPAwB","id":30077617361125376,"from_user_id":79151233,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://tommorris.org/&quot; rel=&quot;nofollow&quot;&gt;tommorris' hacksample&lt;/a&gt;"},{"from_user_id_str":"2331498","profile_image_url":"http://a3.twimg.com/profile_images/494632120/me_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:57 +0000","from_user":"Verus","id_str":"30068139416879104","metadata":{"result_type":"recent"},"to_user_id":9252720,"text":"@shukukei Java\u3068C\u306f\u3042\u308b\u7a0b\u5ea6\u66f8\u3051\u3066\u3042\u305f\u308a\u307e\u3048\u306a\u3068\u3053\u308d\u304c\u3042\u308b\u304b\u3089\u306a\u30fc\uff0ePython\u306f\u500b\u4eba\u7684\u306b\u611f\u899a\u304c\u5408\u308f\u306a\u3044\uff0e\u611f\u899a\u306a\u306e\u3067\uff0c\u3082\u3046\u3069\u3046\u3057\u3088\u3046\u3082\u306a\u3044\uff57 \u3044\u307e\u306fScala\u3068Haskell\u3092\u3082\u3063\u3068\u6975\u3081\u305f\u3044\u3068\u3053\u308d\uff0e","id":30068139416879104,"from_user_id":2331498,"to_user":"shukukei","geo":null,"iso_language_code":"ja","to_user_id_str":"9252720","source":"&lt;a href=&quot;http://itunes.apple.com/us/app/twitter/id409789998?mt=12&quot; rel=&quot;nofollow&quot;&gt;Twitter for Mac&lt;/a&gt;"},{"from_user_id_str":"2781460","profile_image_url":"http://a0.twimg.com/profile_images/82526625/.joeyicon_normal.jpg","created_at":"Wed, 26 Jan 2011 01:02:35 +0000","from_user":"joeyhess","id_str":"30068046538219520","metadata":{"result_type":"recent"},"to_user_id":null,"text":"just figured out that I can use parameterized types to remove a dependency loop in git-annex's type definitions. whee #haskell","id":30068046538219520,"from_user_id":2781460,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://identi.ca&quot; rel=&quot;nofollow&quot;&gt;identica&lt;/a&gt;"},{"from_user_id_str":"144546280","profile_image_url":"http://a1.twimg.com/a/1295051201/images/default_profile_1_normal.png","created_at":"Wed, 26 Jan 2011 00:54:22 +0000","from_user":"listwarenet","id_str":"30065977920061440","metadata":{"result_type":"recent"},"to_user_id":null,"text":"http://www.listware.net/201101/haskell-beginners/84466-haskell-beginners-bytestring-question.html Haskell-beginners -  Bytestrin","id":30065977920061440,"from_user_id":144546280,"geo":null,"iso_language_code":"no","to_user_id_str":null,"source":"&lt;a href=&quot;http://1e10.org/cloud/&quot; rel=&quot;nofollow&quot;&gt;1e10&lt;/a&gt;"},{"from_user_id_str":"1291845","profile_image_url":"http://a0.twimg.com/profile_images/1225743404/ThinOxygen-small-opaque-solidarity_normal.png","created_at":"Wed, 26 Jan 2011 00:52:07 +0000","from_user":"_aaron_","id_str":"30065412242669568","metadata":{"result_type":"recent"},"to_user_id":null,"text":"wanted: librly licensed high level native compiled lang with min runtime (otherwise cobra/mono would be perfect) for win. lua? haskell? ooc?","id":30065412242669568,"from_user_id":1291845,"geo":null,"iso_language_code":"en","to_user_id_str":null,"source":"&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"}],"max_id":30120402839666689,"since_id":0,"refresh_url":"?since_id=30120402839666689&q=haskell","next_page":"?page=2&max_id=30120402839666689&rpp=50&q=haskell","results_per_page":50,"page":1,"completed_in":0.291696,"since_id_str":"0","max_id_str":"30120402839666689","query":"haskell"}
+ word24-bench/Benchmark.hs view
@@ -0,0 +1,32 @@+module Main where++import Criterion.Main+import Control.DeepSeq+import Data.Int.Int24+import Data.Word.Word24+import Data.Int+import Data.Word+import Data.List++main = defaultMain+  [ bgroup "Int24" intses+  , bgroup "Word24" wordses+  , bgroup "Int16"    baseses+  , bgroup "Word16" basessW+  ]++benches :: (Enum i, Num i, NFData i, Integral i) => i -> [Benchmark]+benches x =+   [ bench "Add" $ nf (\i -> foldl' (+) i [1..100]) x+   , bench "Mul" $ nf (\i -> foldl' (*) i [1..100]) x+   , bench "quot" $ nf (\i -> map (flip quot i) [1..25]) x+   , bench "rem" $ nf (\i -> map (flip rem i) [1..25]) x+   , bench "div" $ nf (\i -> map (flip div i) [1..25]) x+   , bench "mod" $ nf (\i -> map (flip mod i) [1..25]) x+   ]+{-# INLINE benches #-}++intses  = benches (1 :: Int24)+wordses = benches (1 :: Word24)+baseses = benches (1 :: Int16)+basessW = benches (1 :: Word16)