Commit 81e4ff initial

12 files Merged and Committed by Richard Marko 2 years ago
initial

    
 1 @@ -0,0 +1,30 @@
 2 + Copyright Author name here (c) 2016
 3 + 
 4 + All rights reserved.
 5 + 
 6 + Redistribution and use in source and binary forms, with or without
 7 + modification, are permitted provided that the following conditions are met:
 8 + 
 9 +     * Redistributions of source code must retain the above copyright
10 +       notice, this list of conditions and the following disclaimer.
11 + 
12 +     * Redistributions in binary form must reproduce the above
13 +       copyright notice, this list of conditions and the following
14 +       disclaimer in the documentation and/or other materials provided
15 +       with the distribution.
16 + 
17 +     * Neither the name of Author name here nor the names of other
18 +       contributors may be used to endorse or promote products derived
19 +       from this software without specific prior written permission.
20 + 
21 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
32 \ No newline at end of file
1 @@ -0,0 +1,2 @@
2 + import Distribution.Simple
3 + main = defaultMain
  1 @@ -0,0 +1,117 @@
  2 + {-# LANGUAGE OverloadedStrings #-}
  3 + {-# LANGUAGE TemplateHaskell #-}
  4 + {-# LANGUAGE RecordWildCards #-}
  5 + module Main where
  6 + 
  7 + import Lens.Micro ((^.), (&), (.~), (%~))
  8 + import Lens.Micro.TH (makeLenses)
  9 + --import Control.Lens
 10 + import Control.Monad (void, forever)
 11 + import Control.Concurrent (newChan, writeChan, threadDelay, forkIO)
 12 + import Data.Default
 13 + import Data.Monoid
 14 + import qualified Graphics.Vty as V
 15 + 
 16 + import Brick.Main
 17 +   ( App(..)
 18 +   , showFirstCursor
 19 +   , customMain
 20 +   , continue
 21 +   , halt
 22 +   )
 23 + import Brick.Types
 24 +   ( Widget
 25 +   , Next
 26 +   , EventM
 27 +   , BrickEvent(..)
 28 +   )
 29 + import Brick.Widgets.Core
 30 +   ( (<=>)
 31 +   , str
 32 +   , txt
 33 +   )
 34 + 
 35 + import Network.Wreq
 36 + import Data.Flypool
 37 + import Data.Aeson
 38 + import Data.Aeson.Lens
 39 + 
 40 + import Text.Printf
 41 + 
 42 + url = "http://zcash.flypool.org/api/miner_new/t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh"
 43 + 
 44 + fetch = do
 45 +   r <- asJSON =<< get url :: IO (Response Flypool)
 46 +   return $ r ^. responseBody
 47 + 
 48 + data CustomEvent = Update Flypool deriving Show
 49 + 
 50 + data St =
 51 +     St { _stLastBrickEvent :: Maybe (BrickEvent () CustomEvent)
 52 +        , _stData :: Maybe Flypool
 53 +        }
 54 + 
 55 + makeLenses ''St
 56 + 
 57 + drawUI :: St -> [Widget ()]
 58 + drawUI st =
 59 +   case st^.stData of
 60 +     Nothing -> [str "Fetching data"]
 61 +     (Just d) -> [global d, workers d]
 62 +   where
 63 +     global Flypool{..} =
 64 +         (str $ "Last update: " <> (show $ st^.stLastBrickEvent))
 65 +         <=>
 66 +         (txt $ "Hashrate " <> hashRate)
 67 +         <=>
 68 +         (txt $ "Reported hashrate " <> reportedHashRate)
 69 +         <=>
 70 +         (str $ "BTC/day " <> (printPrec 8 $ perDay $ btcPerMin))
 71 +         <=>
 72 +         (str $ "ETH/day " <> (printPrec 8 $ perDay $ ethPerMin))
 73 +         <=>
 74 +         (str $ "Unpaid " <> (printPrec 8 $ cvtUnpaid $ unpaid) <> " ZEC")
 75 +         <=>
 76 +         (str $ "Workers " <> (show $ length workers))
 77 +     workers Flypool{..} =
 78 +         (str $ "WAT " <> (show $ length workers))
 79 + 
 80 + perDay x = x*60*24
 81 + printPrec prec = printf $ "%." ++ show prec ++ "f"
 82 + 
 83 + cvtUnpaid x = x/100000000.0
 84 + 
 85 + appEvent :: St -> BrickEvent () CustomEvent -> EventM () (Next St)
 86 + appEvent st e =
 87 +     case e of
 88 +         VtyEvent (V.EvKey V.KEsc []) -> halt st
 89 +         VtyEvent _ -> continue $ st & stLastBrickEvent .~ (Just e)
 90 +         AppEvent (Update n) -> continue $ st & stData .~ (Just n)
 91 +                                           & stLastBrickEvent .~ (Just e)
 92 +         _ -> continue st
 93 + 
 94 + initialState :: St
 95 + initialState =
 96 +     St { _stLastBrickEvent = Nothing
 97 +        , _stData = Nothing
 98 +        }
 99 + 
100 + theApp :: App St CustomEvent ()
101 + theApp =
102 +     App { appDraw = drawUI
103 +         , appChooseCursor = showFirstCursor
104 +         , appHandleEvent = appEvent
105 +         , appStartEvent = return
106 +         , appAttrMap = def
107 +         }
108 + 
109 + main :: IO ()
110 + main = do
111 +     chan <- newChan
112 + 
113 +     forkIO $ forever $ do
114 +         n <- fetch
115 +         writeChan chan (Update n)
116 +         threadDelay 10000000 -- 10s
117 + 
118 +     void $ customMain (V.mkVty def) (Just chan) theApp initialState
 1 @@ -0,0 +1,34 @@
 2 + {-# LANGUAGE OverloadedStrings #-}
 3 + 
 4 + module Main where
 5 + 
 6 + import Control.Lens hiding ((.=))
 7 + import Data.Aeson
 8 + import Data.Aeson.Lens
 9 + import Network.Wreq
10 + import qualified Data.ByteString.Lazy.Char8 as BSL
11 + 
12 + import qualified Data.Text.Lazy as LT
13 + import qualified Data.Text.Lazy.IO as LTIO
14 + import Text.EDE
15 + 
16 + import Data.Flypool
17 + 
18 + url = "http://zcash.flypool.org/api/miner_new/t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh"
19 + 
20 + main :: IO ()
21 + main = do
22 +   --x <- BSL.readFile "test.json"
23 +   --print $ parseBSL x
24 + 
25 +   r <- asJSON =<< get url :: IO (Response Flypool)
26 +   let out = r ^. responseBody
27 +   print out
28 + 
29 +   let jj = (toJSON out) -- :: Object
30 +   case toJSON out of
31 +     Object o -> do
32 +       r <- eitherParseFile "template.ede"
33 +       either error LTIO.putStr $ r >>= (`eitherRender` (o))
34 + 
35 +   return ()
 1 @@ -0,0 +1,79 @@
 2 + {-# LANGUAGE OverloadedStrings #-}
 3 + {-# LANGUAGE TemplateHaskell #-}
 4 + module Main where
 5 + 
 6 + import Lens.Micro ((^.), (&), (.~), (%~))
 7 + import Lens.Micro.TH (makeLenses)
 8 + import Control.Monad (void, forever)
 9 + import Control.Concurrent (newChan, writeChan, threadDelay, forkIO)
10 + import Data.Default
11 + import Data.Monoid
12 + import qualified Graphics.Vty as V
13 + 
14 + import Brick.Main
15 +   ( App(..)
16 +   , showFirstCursor
17 +   , customMain
18 +   , continue
19 +   , halt
20 +   )
21 + import Brick.Types
22 +   ( Widget
23 +   , Next
24 +   , EventM
25 +   , BrickEvent(..)
26 +   )
27 + import Brick.Widgets.Core
28 +   ( (<=>)
29 +   , str
30 +   )
31 + 
32 + data CustomEvent = Counter deriving Show
33 + 
34 + data St =
35 +     St { _stLastBrickEvent :: Maybe (BrickEvent () CustomEvent)
36 +        , _stCounter :: Int
37 +        }
38 + 
39 + makeLenses ''St
40 + 
41 + drawUI :: St -> [Widget ()]
42 + drawUI st = [a]
43 +     where
44 +         a = (str $ "Last event: " <> (show $ st^.stLastBrickEvent))
45 +             <=>
46 +             (str $ "Counter value is: " <> (show $ st^.stCounter))
47 + 
48 + appEvent :: St -> BrickEvent () CustomEvent -> EventM () (Next St)
49 + appEvent st e =
50 +     case e of
51 +         VtyEvent (V.EvKey V.KEsc []) -> halt st
52 +         VtyEvent _ -> continue $ st & stLastBrickEvent .~ (Just e)
53 +         AppEvent Counter -> continue $ st & stCounter %~ (+1)
54 +                                           & stLastBrickEvent .~ (Just e)
55 +         _ -> continue st
56 + 
57 + initialState :: St
58 + initialState =
59 +     St { _stLastBrickEvent = Nothing
60 +        , _stCounter = 0
61 +        }
62 + 
63 + theApp :: App St CustomEvent ()
64 + theApp =
65 +     App { appDraw = drawUI
66 +         , appChooseCursor = showFirstCursor
67 +         , appHandleEvent = appEvent
68 +         , appStartEvent = return
69 +         , appAttrMap = def
70 +         }
71 + 
72 + main :: IO ()
73 + main = do
74 +     chan <- newChan
75 + 
76 +     forkIO $ forever $ do
77 +         writeChan chan Counter
78 +         threadDelay 1000000
79 + 
80 +     void $ customMain (V.mkVty def) (Just chan) theApp initialState
 1 @@ -0,0 +1,59 @@
 2 + name:                flypoolhs
 3 + version:             0.1.0.0
 4 + synopsis:            Initial project template from stack
 5 + description:         Please see README.md
 6 + homepage:            https://github.com/githubuser/flypoolhs#readme
 7 + license:             BSD3
 8 + license-file:        LICENSE
 9 + author:              Richard Marko
10 + maintainer:          srk@48.io
11 + copyright:           2016 Richard Marko
12 + category:            Web
13 + build-type:          Simple
14 + -- extra-source-files:
15 + cabal-version:       >=1.10
16 + 
17 + library
18 +   hs-source-dirs:      src
19 +   exposed-modules:     Data.Flypool
20 +   build-depends:       base >= 4.7 && < 5
21 +                      , aeson
22 +                      , bytestring
23 +                      , containers
24 +                      , text
25 +                      , time
26 +                      , json-autotype
27 +   default-language:    Haskell2010
28 + 
29 + executable flypoolhs
30 +   hs-source-dirs:      app
31 +   main-is:             Main.hs
32 +   ghc-options:         -threaded -rtsopts -with-rtsopts=-N
33 +   build-depends:       base
34 +                      , bytestring
35 +                      , brick
36 +                      , data-default
37 +                      , aeson
38 +                      , ede
39 +                      , microlens
40 +                      , microlens-th
41 +                      , vty
42 +                      , wreq
43 +                      , lens
44 +                      , lens-aeson
45 +                      , text
46 +                      , flypoolhs
47 +   default-language:    Haskell2010
48 + 
49 + test-suite flypoolhs-test
50 +   type:                exitcode-stdio-1.0
51 +   hs-source-dirs:      test
52 +   main-is:             Spec.hs
53 +   build-depends:       base
54 +                      , flypoolhs
55 +   ghc-options:         -threaded -rtsopts -with-rtsopts=-N
56 +   default-language:    Haskell2010
57 + 
58 + source-repository head
59 +   type:     git
60 +   location: https://github.com/githubuser/flypoolhs
  1 @@ -0,0 +1,101 @@
  2 + {
  3 +   "address": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
  4 +   "hashRate": "38.3H\/s",
  5 +   "reportedHashRate": "0.0H\/s",
  6 +   "payouts": [
  7 +     
  8 +   ],
  9 +   "workers": {
 10 +     "b": {
 11 +       "worker": "b",
 12 +       "hashrate": "1.7H\/s",
 13 +       "validShares": 1,
 14 +       "invalidShares": 0,
 15 +       "workerLastSubmitTime": 1479063189,
 16 +       "staleShares": 0,
 17 +       "invalidShareRatio": 0
 18 +     },
 19 +     "d": {
 20 +       "worker": "d",
 21 +       "hashrate": "18.3H\/s",
 22 +       "validShares": 11,
 23 +       "invalidShares": 0,
 24 +       "workerLastSubmitTime": 1479063511,
 25 +       "staleShares": 0,
 26 +       "invalidShareRatio": 0
 27 +     },
 28 +     "pg": {
 29 +       "worker": "pg",
 30 +       "hashrate": "18.3H\/s",
 31 +       "validShares": 11,
 32 +       "invalidShares": 0,
 33 +       "workerLastSubmitTime": 1479063537,
 34 +       "staleShares": 0,
 35 +       "invalidShareRatio": 0
 36 +     }
 37 +   },
 38 +   "settings": {
 39 +     "email": "",
 40 +     "monitor": 0,
 41 +     "name": "",
 42 +     "minPayout": 1,
 43 +     "vote": 0,
 44 +     "ip": "*.*.*.120",
 45 +     "voteip": ""
 46 +   },
 47 +   "ethPerMin": 2.2047617924848e-7,
 48 +   "usdPerMin": 0,
 49 +   "btcPerMin": 4.1229047724228e-8,
 50 +   "avgHashrate": 1.3513513513514,
 51 +   "rounds": [
 52 +     {
 53 +       "id": 15062455,
 54 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 55 +       "block": 9652,
 56 +       "work": 38,
 57 +       "amount": 4547,
 58 +       "processed": 0
 59 +     },
 60 +     {
 61 +       "id": 15054033,
 62 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 63 +       "block": 9651,
 64 +       "work": 28,
 65 +       "amount": 3373,
 66 +       "processed": 0
 67 +     },
 68 +     {
 69 +       "id": 15045229,
 70 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 71 +       "block": 9639,
 72 +       "work": 10,
 73 +       "amount": 1178,
 74 +       "processed": 0
 75 +     },
 76 +     {
 77 +       "id": 15037114,
 78 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 79 +       "block": 9636,
 80 +       "work": 12,
 81 +       "amount": 1381,
 82 +       "processed": 0
 83 +     },
 84 +     {
 85 +       "id": 15020457,
 86 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 87 +       "block": 9635,
 88 +       "work": 7,
 89 +       "amount": 781,
 90 +       "processed": 0
 91 +     },
 92 +     {
 93 +       "id": 15028650,
 94 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 95 +       "block": 9634,
 96 +       "work": 7,
 97 +       "amount": 781,
 98 +       "processed": 0
 99 +     }
100 +   ],
101 +   "unpaid": 12041
102 + }
  1 @@ -0,0 +1,131 @@
  2 + {-# LANGUAGE TemplateHaskell     #-}
  3 + {-# LANGUAGE ScopedTypeVariables #-}
  4 + {-# LANGUAGE RecordWildCards     #-}
  5 + {-# LANGUAGE OverloadedStrings   #-}
  6 + {-# LANGUAGE TypeOperators       #-}
  7 + {-# LANGUAGE DeriveGeneric       #-}
  8 + 
  9 + -- generated by json-autotype, heavily modified afterwards
 10 + -- json-autotype sample.json
 11 + 
 12 + module Data.Flypool (parseBSL, Flypool(..)) where
 13 + 
 14 + import           System.Exit        (exitFailure, exitSuccess)
 15 + import           System.IO          (stderr, hPutStrLn)
 16 + import qualified Data.ByteString.Lazy.Char8 as BSL
 17 + import           System.Environment (getArgs)
 18 + import           Control.Monad      (forM_, mzero, join)
 19 + import           Control.Applicative
 20 + import           Data.Aeson.AutoType.Alternative
 21 + import           Data.Aeson(decode, Value(..), FromJSON(..), ToJSON(..),
 22 +                             pairs,
 23 +                             (.:), (.:?), (.=), object)
 24 + import           Data.Monoid
 25 + import           Data.Text (Text)
 26 + import           GHC.Generics
 27 + import           Data.Map
 28 + --import           Data.Time.Clock
 29 + 
 30 + -- | Workaround for https://github.com/bos/aeson/issues/287.
 31 + o .:?? val = fmap join (o .:? val)
 32 + 
 33 + data Settings = Settings {
 34 +     settingsEmail :: Text,
 35 +     settingsIp :: Text,
 36 +     settingsMonitor :: Double,
 37 +     settingsMinPayout :: Double,
 38 +     settingsName :: Text,
 39 +     settingsVote :: Double,
 40 +     settingsVoteip :: Text
 41 +   } deriving (Show,Eq,Generic)
 42 + 
 43 + instance FromJSON Settings where
 44 +   parseJSON (Object v) = Settings <$> v .:   "email" <*> v .:   "ip" <*> v .:   "monitor" <*> v .:   "minPayout" <*> v .:   "name" <*> v .:   "vote" <*> v .:   "voteip"
 45 +   parseJSON _          = mzero
 46 + 
 47 + instance ToJSON Settings where
 48 +   toJSON     (Settings {..}) = object ["email" .= settingsEmail, "ip" .= settingsIp, "monitor" .= settingsMonitor, "minPayout" .= settingsMinPayout, "name" .= settingsName, "vote" .= settingsVote, "voteip" .= settingsVoteip]
 49 +   toEncoding (Settings {..}) = pairs  ("email" .= settingsEmail<>"ip" .= settingsIp<>"monitor" .= settingsMonitor<>"minPayout" .= settingsMinPayout<>"name" .= settingsName<>"vote" .= settingsVote<>"voteip" .= settingsVoteip)
 50 + 
 51 + data Worker = Worker {
 52 +     invalidShares :: Double,
 53 +     workerLastSubmitTime :: Double,
 54 +     validShares :: Double,
 55 +     invalidShareRatio :: Double,
 56 +     hashrate :: Text,
 57 +     worker :: Text,
 58 +     staleShares :: Double
 59 +   } deriving (Show,Eq,Generic)
 60 + 
 61 + instance FromJSON Worker where
 62 +   parseJSON (Object v) = Worker <$> v .:   "invalidShares" <*> v .:   "workerLastSubmitTime" <*> v .:   "validShares" <*> v .:   "invalidShareRatio" <*> v .:   "hashrate" <*> v .:   "worker" <*> v .:   "staleShares"
 63 +   parseJSON _          = mzero
 64 + 
 65 + instance ToJSON Worker where
 66 +   toJSON     (Worker {..}) = object ["invalidShares" .= invalidShares, "workerLastSubmitTime" .= workerLastSubmitTime, "validShares" .= validShares, "invalidShareRatio" .= invalidShareRatio, "hashrate" .= hashrate, "worker" .= worker, "staleShares" .= staleShares]
 67 +   toEncoding (Worker {..}) = pairs  ("invalidShares" .= invalidShares<>"workerLastSubmitTime" .= workerLastSubmitTime<>"validShares" .= validShares<>"invalidShareRatio" .= invalidShareRatio<>"hashrate" .= hashrate<>"worker" .= worker<>"staleShares" .= staleShares)
 68 + 
 69 + data RoundsElt = RoundsElt {
 70 +     roundsEltAmount :: Double,
 71 +     roundsEltMiner :: Text,
 72 +     roundsEltBlock :: Double,
 73 +     roundsEltProcessed :: Double,
 74 +     roundsEltId :: Double,
 75 +     roundsEltWork :: Double
 76 +   } deriving (Show,Eq,Generic)
 77 + 
 78 + 
 79 + instance FromJSON RoundsElt where
 80 +   parseJSON (Object v) = RoundsElt <$> v .:   "amount" <*> v .:   "miner" <*> v .:   "block" <*> v .:   "processed" <*> v .:   "id" <*> v .:   "work"
 81 +   parseJSON _          = mzero
 82 + 
 83 + 
 84 + instance ToJSON RoundsElt where
 85 +   toJSON     (RoundsElt {..}) = object ["amount" .= roundsEltAmount, "miner" .= roundsEltMiner, "block" .= roundsEltBlock, "processed" .= roundsEltProcessed, "id" .= roundsEltId, "work" .= roundsEltWork]
 86 +   toEncoding (RoundsElt {..}) = pairs  ("amount" .= roundsEltAmount<>"miner" .= roundsEltMiner<>"block" .= roundsEltBlock<>"processed" .= roundsEltProcessed<>"id" .= roundsEltId<>"work" .= roundsEltWork)
 87 + 
 88 + 
 89 + data Flypool = Flypool {
 90 +     ethPerMin :: Double,
 91 +     unpaid :: Double,
 92 +     settings :: Settings,
 93 +     btcPerMin :: Double,
 94 +     address :: Text,
 95 +     reportedHashRate :: Text,
 96 +     usdPerMin :: Double,
 97 +     payouts :: [(Maybe Value)],
 98 +     workers :: Map Text Worker,
 99 +     hashRate :: Text,
100 +     avgHashrate :: Double,
101 +     rounds :: [RoundsElt]
102 +   } deriving (Show,Eq,Generic)
103 + 
104 + instance FromJSON Flypool where
105 +   parseJSON (Object v) = Flypool <$> v .:   "ethPerMin" <*> v .:   "unpaid" <*> v .:   "settings" <*> v .:   "btcPerMin" <*> v .:   "address" <*> v .:   "reportedHashRate" <*> v .:   "usdPerMin" <*> v .:   "payouts" <*> v .:   "workers" <*> v .:   "hashRate" <*> v .:   "avgHashrate" <*> v .:   "rounds"
106 +   parseJSON _          = mzero
107 + 
108 + instance ToJSON Flypool where
109 +   toJSON     (Flypool {..}) = object ["ethPerMin" .= ethPerMin, "unpaid" .= unpaid, "settings" .= settings, "btcPerMin" .= btcPerMin, "address" .= address, "reportedHashRate" .= reportedHashRate, "usdPerMin" .= usdPerMin, "payouts" .= payouts, "workers" .= workers, "hashRate" .= hashRate, "avgHashrate" .= avgHashrate, "rounds" .= rounds]
110 +   toEncoding (Flypool {..}) = pairs  ("ethPerMin" .= ethPerMin<>"unpaid" .= unpaid<>"settings" .= settings<>"btcPerMin" .= btcPerMin<>"address" .= address<>"reportedHashRate" .= reportedHashRate<>"usdPerMin" .= usdPerMin<>"payouts" .= payouts<>"workers" .= workers<>"hashRate" .= hashRate<>"avgHashrate" .= avgHashrate<>"rounds" .= rounds)
111 + 
112 + 
113 + parse :: FilePath -> IO Flypool
114 + parse filename = do input <- BSL.readFile filename
115 +                     case decode input of
116 +                       Nothing -> fatal $ case (decode input :: Maybe Value) of
117 +                                            Nothing -> "Invalid JSON file: "     ++ filename
118 +                                            Just v  -> "Mismatched JSON value from file: " ++ filename
119 +                       Just r  -> return (r :: Flypool)
120 +   where
121 +     fatal :: String -> IO a
122 +     fatal msg = do hPutStrLn stderr msg
123 +                    exitFailure
124 + 
125 + parseBSL :: BSL.ByteString -> Maybe Flypool
126 + parseBSL input = decode input
127 + 
128 + main :: IO ()
129 + main = do
130 +   filenames <- getArgs
131 +   forM_ filenames (\f -> parse f >>= (\p -> p `seq` putStrLn $ "Successfully parsed " ++ f ++ "\n" ++ (show p)))
132 +   exitSuccess
 1 @@ -0,0 +1,68 @@
 2 + # This file was automatically generated by 'stack init'
 3 + # 
 4 + # Some commonly used options have been documented as comments in this file.
 5 + # For advanced use and comprehensive documentation of the format, please see:
 6 + # http://docs.haskellstack.org/en/stable/yaml_configuration/
 7 + 
 8 + # Resolver to choose a 'specific' stackage snapshot or a compiler version.
 9 + # A snapshot resolver dictates the compiler version and the set of packages
10 + # to be used for project dependencies. For example:
11 + # 
12 + # resolver: lts-3.5
13 + # resolver: nightly-2015-09-21
14 + # resolver: ghc-7.10.2
15 + # resolver: ghcjs-0.1.0_ghc-7.10.2
16 + # resolver:
17 + #  name: custom-snapshot
18 + #  location: "./custom-snapshot.yaml"
19 + resolver: lts-7.8
20 + 
21 + # User packages to be built.
22 + # Various formats can be used as shown in the example below.
23 + # 
24 + # packages:
25 + # - some-directory
26 + # - https://example.com/foo/bar/baz-0.0.2.tar.gz
27 + # - location:
28 + #    git: https://github.com/commercialhaskell/stack.git
29 + #    commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
30 + # - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
31 + #   extra-dep: true
32 + #  subdirs:
33 + #  - auto-update
34 + #  - wai
35 + # 
36 + # A package marked 'extra-dep: true' will only be built if demanded by a
37 + # non-dependency (i.e. a user package), and its test suites and benchmarks
38 + # will not be run. This is useful for tweaking upstream packages.
39 + packages:
40 + - '.'
41 + # Dependency packages to be pulled from upstream that are not in the resolver
42 + # (e.g., acme-missiles-0.3)
43 + extra-deps:
44 + - brick-0.13
45 + - text-zipper-0.8.3
46 + 
47 + # Override default flag values for local packages and extra-deps
48 + flags: {}
49 + 
50 + # Extra package databases containing global packages
51 + extra-package-dbs: []
52 + 
53 + # Control whether we use the GHC we find on the path
54 + # system-ghc: true
55 + # 
56 + # Require a specific version of stack, using version ranges
57 + # require-stack-version: -any # Default
58 + # require-stack-version: ">=1.1"
59 + # 
60 + # Override the architecture used by stack, especially useful on Windows
61 + # arch: i386
62 + # arch: x86_64
63 + # 
64 + # Extra directories used by stack for building
65 + # extra-include-dirs: [/path/to/dir]
66 + # extra-lib-dirs: [/path/to/dir]
67 + # 
68 + # Allow a newer minor version of GHC than the snapshot specifies
69 + # compiler-check: newer-minor
 1 @@ -0,0 +1,10 @@
 2 + hashrate {{ hashRate }}
 3 + ETH/24h: {{ ethPerMin * 3600 * 24 }}
 4 + BTC/24h: {{ btcPerMin * 3600 * 24 }}
 5 + unpaid {{ unpaid * 0.1000 }}
 6 + 
 7 + {% for item in workers %}
 8 +  {{ item.key }}
 9 +  {{ item.value.hashrate }}
10 +  {{ item.value | show }}
11 + {% endfor %}
  1 @@ -0,0 +1,101 @@
  2 + {
  3 +   "address": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
  4 +   "hashRate": "38.3H\/s",
  5 +   "reportedHashRate": "0.0H\/s",
  6 +   "payouts": [
  7 +     
  8 +   ],
  9 +   "workers": {
 10 +     "b": {
 11 +       "worker": "b",
 12 +       "hashrate": "1.7H\/s",
 13 +       "validShares": 1,
 14 +       "invalidShares": 0,
 15 +       "workerLastSubmitTime": 1479063189,
 16 +       "staleShares": 0,
 17 +       "invalidShareRatio": 0
 18 +     },
 19 +     "d": {
 20 +       "worker": "d",
 21 +       "hashrate": "18.3H\/s",
 22 +       "validShares": 11,
 23 +       "invalidShares": 0,
 24 +       "workerLastSubmitTime": 1479063511,
 25 +       "staleShares": 0,
 26 +       "invalidShareRatio": 0
 27 +     },
 28 +     "pg": {
 29 +       "worker": "pg",
 30 +       "hashrate": "18.3H\/s",
 31 +       "validShares": 11,
 32 +       "invalidShares": 0,
 33 +       "workerLastSubmitTime": 1479063537,
 34 +       "staleShares": 0,
 35 +       "invalidShareRatio": 0
 36 +     }
 37 +   },
 38 +   "settings": {
 39 +     "email": "",
 40 +     "monitor": 0,
 41 +     "name": "",
 42 +     "minPayout": 1,
 43 +     "vote": 0,
 44 +     "ip": "*.*.*.120",
 45 +     "voteip": ""
 46 +   },
 47 +   "ethPerMin": 2.2047617924848e-7,
 48 +   "usdPerMin": 0,
 49 +   "btcPerMin": 4.1229047724228e-8,
 50 +   "avgHashrate": 1.3513513513514,
 51 +   "rounds": [
 52 +     {
 53 +       "id": 15062455,
 54 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 55 +       "block": 9652,
 56 +       "work": 38,
 57 +       "amount": 4547,
 58 +       "processed": 0
 59 +     },
 60 +     {
 61 +       "id": 15054033,
 62 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 63 +       "block": 9651,
 64 +       "work": 28,
 65 +       "amount": 3373,
 66 +       "processed": 0
 67 +     },
 68 +     {
 69 +       "id": 15045229,
 70 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 71 +       "block": 9639,
 72 +       "work": 10,
 73 +       "amount": 1178,
 74 +       "processed": 0
 75 +     },
 76 +     {
 77 +       "id": 15037114,
 78 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 79 +       "block": 9636,
 80 +       "work": 12,
 81 +       "amount": 1381,
 82 +       "processed": 0
 83 +     },
 84 +     {
 85 +       "id": 15020457,
 86 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 87 +       "block": 9635,
 88 +       "work": 7,
 89 +       "amount": 781,
 90 +       "processed": 0
 91 +     },
 92 +     {
 93 +       "id": 15028650,
 94 +       "miner": "t1VPLA9KSN2BfH1evH8HVBNnnNroepcLYyh",
 95 +       "block": 9634,
 96 +       "work": 7,
 97 +       "amount": 781,
 98 +       "processed": 0
 99 +     }
100 +   ],
101 +   "unpaid": 12041
102 + }
1 @@ -0,0 +1,2 @@
2 + main :: IO ()
3 + main = putStrLn "Test suite not yet implemented"