packages feed

battleplace (empty) → 0.1.0.0

raw patch · 8 files changed

+646/−0 lines, 8 filesdep +aesondep +basedep +bytestring

Dependencies added: aeson, base, bytestring, cereal, data-default, hashable, memory, servant, text, vector

Files

+ BattlePlace/Rating.hs view
@@ -0,0 +1,16 @@+{-|+Module: BattlePlace.Rating+Description: Rating type.+License: MIT+-}++{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module BattlePlace.Rating+	( Rating(..)+	) where++import qualified Data.Aeson as J++-- | User rating.+newtype Rating = Rating Double deriving (Eq, Ord, J.FromJSON, J.ToJSON)
+ BattlePlace/Skill/Glicko/Types.hs view
@@ -0,0 +1,46 @@+{-|+Module: BattlePlace.Skill.Glicko.Types+Description: Types for Glicko ratings.+License: MIT+-}++{-# LANGUAGE DeriveGeneric #-}++module BattlePlace.Skill.Glicko.Types+	( Skill(..)+	, ratingFromSkill+	) where++import qualified Data.Aeson as J+import Data.Default+import GHC.Generics(Generic)++import BattlePlace.Rating+import BattlePlace.Util++data Skill = Skill+	{ skill_rating :: {-# UNPACK #-} !Double+	, skill_deviation :: {-# UNPACK #-} !Double+	, skill_volatility :: {-# UNPACK #-} !Double+	} deriving Generic++-- default skill+instance Default (Skill) where+	def = Skill+		{ skill_rating = 1500+		, skill_deviation = 350+		, skill_volatility = 0.06+		}++instance J.FromJSON (Skill) where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON (Skill) where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++-- | Conservative rating for skill.+ratingFromSkill :: Skill -> Rating+ratingFromSkill Skill+	{ skill_rating = rating+	, skill_deviation = deviation+	} = Rating $ rating - deviation * 2
+ BattlePlace/Token/Types.hs view
@@ -0,0 +1,24 @@+{-|+Module: BattlePlace.Token.Types+Description: Token types.+License: MIT+-}++{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module BattlePlace.Token.Types+	( InternalToken(..)+	, Ticket(..)+	) where++import qualified Data.Aeson as J+import qualified Data.Text as T+import Servant.API++-- | Internal token.+-- Token is encrypted, and contains some internal information.+newtype InternalToken a = InternalToken T.Text deriving (J.FromJSON, J.ToJSON, FromHttpApiData, ToHttpApiData)++-- | Ticket.+-- Ticket doesn't contain information, it's just an ID.+newtype Ticket = Ticket T.Text deriving (J.FromJSON, J.ToJSON)
+ BattlePlace/Util.hs view
@@ -0,0 +1,35 @@+{-|+Module: BattlePlace.Util+Description: General utilities.+License: MIT+-}++{-# LANGUAGE LambdaCase #-}++module BattlePlace.Util+	( jsonOptions+	, jsonOptionsWithTag+	) where++import qualified Data.Aeson as J++jsonOptions :: J.Options+jsonOptions = jsonOptionsWithTag "status"++jsonOptionsWithTag :: String -> J.Options+jsonOptionsWithTag tag = J.defaultOptions+	{ J.fieldLabelModifier = dropBeforeUnderscore+	, J.constructorTagModifier = dropBeforeUnderscore+	, J.sumEncoding = J.TaggedObject+		{ J.tagFieldName = tag+		, J.contentsFieldName = "contents"+		}+	}++dropBeforeUnderscore :: String -> String+dropBeforeUnderscore = \case+	x : xs -> case x of+		'_' -> xs+		_ -> dropBeforeUnderscore xs+	[] -> []+
+ BattlePlace/WebApi.hs view
@@ -0,0 +1,226 @@+{-|+Module: BattlePlace.WebApi+Description: Web API definitions.+License: MIT+-}++{-# LANGUAGE DataKinds, DeriveGeneric, GeneralizedNewtypeDeriving, TypeOperators #-}++module BattlePlace.WebApi+	( WebApi+	, ClientAuthRequest(..)+	, ClientAuthResponse(..)+	, MatchRequest(..)+	, MatchResponse(..)+	, MatchStatusResponse(..)+	, MatchStatusReason(..)+	, MatchTeam(..)+	, MatchPlayer(..)+	, MatchServer(..)+	, MatchServerInfo(..)+	, SessionResultRequest(..)+	, ServerMatchRequest(..)+	, ServerMatchResponse(..)+	, ServerSessionResultRequest(..)+	, ServerSession(..)+	) where++import qualified Data.Aeson as J+import qualified Data.Text as T+import qualified Data.Vector as V+import qualified Data.Vector.Unboxed as VU+import GHC.Generics(Generic)+import Servant.API++import BattlePlace.Token.Types+import BattlePlace.Util+import BattlePlace.WebApi.Types++type WebApi = "v1a" :>+	(    "client" :>+		(    "auth" :> ReqBody '[JSON] ClientAuthRequest :> Post '[JSON] ClientAuthResponse+		:<|> "match" :>+			(    ReqBody '[JSON] MatchRequest :> Post '[JSON] MatchResponse+			:<|> Capture "matchToken" (InternalToken MatchToken) :> Get '[JSON] MatchStatusResponse+			)+		:<|> "session" :> Capture "sessionToken" (InternalToken SessionToken) :>+			(    "result" :> ReqBody '[JSON] SessionResultRequest :> Post '[JSON] ()+			)+		)+	:<|> "server" :>+		(    "match" :> ReqBody '[JSON] ServerMatchRequest :> Post '[JSON] ServerMatchResponse+		:<|> "session" :> Capture "serverSessionToken" (InternalToken ServerSessionToken) :>+			(    "result" :> ReqBody '[JSON] ServerSessionResultRequest :> Post '[JSON] ()+			)+		)+	)++data ClientAuthRequest = ClientAuthRequest+	{ clientAuthRequest_projectId :: {-# UNPACK #-} !ProjectId+	, clientAuthRequest_auth :: !Auth+	} deriving Generic+instance J.FromJSON ClientAuthRequest where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON ClientAuthRequest where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++data ClientAuthResponse+	= ClientAuthResponse_authenticated+		{ clientAuthResponse_clientToken :: !(InternalToken ClientToken)+		, clientAuthResponse_name :: !T.Text+		, clientAuthResponse_pictureUrl :: !T.Text+		}+	| ClientAuthResponse_notAuthenticated+		{ clientAuthResponse_error :: !T.Text+		}+	deriving Generic+instance J.FromJSON ClientAuthResponse where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON ClientAuthResponse where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++data MatchRequest = MatchRequest+	{ matchRequest_clientToken :: !(InternalToken ClientToken)+	, matchRequest_teamSizes :: !(VU.Vector MatchTeamSize)+	, matchRequest_maxMatchTime :: {-# UNPACK #-} !Int+	, matchRequest_matchTag :: !(Maybe MatchTag)+	, matchRequest_info :: !(Maybe MatchPlayerInfo)+	} deriving Generic+instance J.FromJSON MatchRequest where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON MatchRequest where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++data MatchResponse = MatchResponse+	{ matchResponse_matchToken :: !(InternalToken MatchToken)+	} deriving Generic+instance J.FromJSON MatchResponse where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON MatchResponse where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++data MatchStatusResponse+	= MatchStatusResponse_notFound+	| MatchStatusResponse_inProgress+	| MatchStatusResponse_matched+		{ matchStatusResponse_sessionId :: !SessionId+		, matchStatusResponse_sessionToken :: !(InternalToken SessionToken)+		, matchStatusResponse_teams :: !(V.Vector MatchTeam)+		, matchStatusResponse_teamIndex :: {-# UNPACK #-} !Int+		, matchStatusResponse_mateIndex :: {-# UNPACK #-} !Int+		, matchStatusResponse_server :: !(Maybe MatchServer)+		}+	| MatchStatusResponse_failed+		{ matchStatusResponse_reason :: !MatchStatusReason+		}+	-- | Match status was cleaned.+	-- Normallly this status should not be visible to clients, it's here just in case.+	| MatchStatusResponse_cleaned+	deriving Generic+instance J.FromJSON MatchStatusResponse where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON MatchStatusResponse where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++-- | Reason of match failure.+data MatchStatusReason+	-- | Failed to make a match in a specified time.+	= MatchStatusReason_timedOut+	-- | Match was made, but no server is available (and use of server is mandatory).+	| MatchStatusReason_noServer+	-- | Matching was explicitly cancelled by user.+	| MatchStatusReason_cancelled+	deriving Generic+instance J.FromJSON MatchStatusReason where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON MatchStatusReason where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++newtype MatchTeam = MatchTeam (V.Vector MatchPlayer) deriving (J.FromJSON, J.ToJSON)++data MatchPlayer = MatchPlayer+	{ matchPlayer_info :: !MatchPlayerInfo+	, matchPlayer_ourTicket :: !(Maybe Ticket)+	, matchPlayer_theirTicket :: !(Maybe Ticket)+	} deriving Generic+instance J.FromJSON MatchPlayer where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON MatchPlayer where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++data MatchServer = MatchServer+	{ matchServer_info :: !MatchServerInfo+	, matchServer_ourTicket :: !Ticket+	, matchServer_theirTicket :: !Ticket+	} deriving Generic+instance J.FromJSON MatchServer where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON MatchServer where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++newtype MatchServerInfo = MatchServerInfo T.Text deriving (J.FromJSON, J.ToJSON)++data SessionResultRequest+	= SessionResultRequest_finished+		{ sessionResultRequest_ranks :: !(V.Vector Int)+		}+	| SessionResultRequest_cancelled+	deriving Generic+instance J.FromJSON SessionResultRequest where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON SessionResultRequest where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++data ServerMatchRequest = ServerMatchRequest+	{ serverMatchRequest_projectId :: {-# UNPACK #-} !ProjectId+	, serverMatchRequest_projectServerToken :: !ProjectServerToken+	, serverMatchRequest_maxSessionsCount :: {-# UNPACK #-} !Int+	, serverMatchRequest_info :: !MatchServerInfo+	, serverMatchRequest_timeout :: !(Maybe Int)+	} deriving Generic+instance J.FromJSON ServerMatchRequest where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON ServerMatchRequest where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++data ServerMatchResponse = ServerMatchResponse+	{ serverMatchResponse_sessions :: !(V.Vector ServerSession)+	} deriving Generic+instance J.FromJSON ServerMatchResponse where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON ServerMatchResponse where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++data ServerSessionResultRequest+	= ServerSessionResultRequest_finished+		{ serverSessionResultRequest_ranks :: !(V.Vector Int)+		}+	| ServerSessionResultRequest_cancelled+	deriving Generic+instance J.FromJSON ServerSessionResultRequest where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON ServerSessionResultRequest where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++data ServerSession = ServerSession+	{ serverSession_sessionId :: !SessionId+	, serverSession_serverSessionToken :: !(InternalToken ServerSessionToken)+	, serverSession_teams :: !(V.Vector MatchTeam)+	} deriving Generic+instance J.FromJSON ServerSession where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON ServerSession where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions
+ BattlePlace/WebApi/Types.hs view
@@ -0,0 +1,243 @@+{-|+Module: BattlePlace.WebApi.Types+Description: Web API types.+License: MIT+-}++{-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving, LambdaCase, ViewPatterns #-}++module BattlePlace.WebApi.Types+	( AccountId(..)+	, ProjectId(..)+	, Auth(..)+	, AuthType(..)+	, authTypeOf+	, Client(..)+	, ClientToken(..)+	, ProjectServerId(..)+	, ProjectServerToken(..)+	, MatchTeamSize+	, MatchTag(..)+	, MatchPlayerInfo(..)+	, MatchToken(..)+	, SessionToken(..)+	, SessionId(..)+	, ServerSessionToken(..)+	, Identified(..)+	, Base64ByteString(..)+	, Base64Word64(..)+	, StrWord64(..)+	) where++import Control.Monad+import qualified Data.Aeson as J+import qualified Data.Aeson.Types as J+import qualified Data.ByteArray as BA+import qualified Data.ByteArray.Encoding as BA+import qualified Data.ByteString as B+import Data.Either+import Data.Hashable+import qualified Data.Serialize as S+import Data.String+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Data.Word+import Foreign.Storable+import GHC.Generics(Generic)+import Servant.API++import BattlePlace.Util++-- | Account id.+-- At the moment it's just itch user id, but that may change.+newtype AccountId = AccountId Base64Word64 deriving (J.FromJSON, J.ToJSON, FromHttpApiData)++-- | Project id.+newtype ProjectId = ProjectId Base64Word64 deriving (Eq, Hashable, J.FromJSON, J.ToJSON, FromHttpApiData)++data Auth+	= Auth_itchJwtToken+		{ auth_itchJwtToken :: !T.Text+		}+	| Auth_steamEncryptedTicket+		{ auth_steamEncryptedTicket :: !T.Text+		}+	| Auth_testKey+		{ auth_testKey :: !T.Text+		, auth_testId :: !StrWord64+		}+	deriving Generic+instance J.FromJSON Auth where+	parseJSON = J.genericParseJSON jsonOptions+		{ J.sumEncoding = J.UntaggedValue+		}+instance J.ToJSON Auth where+	toJSON = J.genericToJSON jsonOptions+		{ J.sumEncoding = J.UntaggedValue+		}+	toEncoding = J.genericToEncoding jsonOptions+		{ J.sumEncoding = J.UntaggedValue+		}++-- | Auth type (for logging).+data AuthType+	= AuthType_itchJwtToken+	| AuthType_steamEncryptedTicket+	| AuthType_testKey+	deriving Generic+instance J.FromJSON AuthType where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON AuthType where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++authTypeOf :: Auth -> AuthType+authTypeOf = \case+	Auth_itchJwtToken {} -> AuthType_itchJwtToken+	Auth_steamEncryptedTicket {} -> AuthType_steamEncryptedTicket+	Auth_testKey {} -> AuthType_testKey++data Client+	= Client_itch+		{ client_itchUserId :: {-# UNPACK #-} !StrWord64+		}+	| Client_steam+		{ client_steamId :: {-# UNPACK #-} !StrWord64+		}+	| Client_test+		{ client_testId :: {-# UNPACK #-} !StrWord64+		}+	deriving (Eq, Generic)+instance Hashable Client+instance J.FromJSON Client where+	parseJSON = J.genericParseJSON $ jsonOptionsWithTag "type"+instance J.ToJSON Client where+	toJSON = J.genericToJSON $ jsonOptionsWithTag "type"+	toEncoding = J.genericToEncoding $ jsonOptionsWithTag "type"++data ClientToken = ClientToken+	{ clientToken_projectId :: {-# UNPACK #-} !ProjectId+	, clientToken_client :: !Client+	} deriving Generic+instance J.FromJSON ClientToken where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON ClientToken where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++-- | Project's server id.+newtype ProjectServerId = ProjectServerId Base64Word64 deriving (Eq, Hashable, J.FromJSON, J.FromJSONKey, J.ToJSON, J.ToJSONKey)++-- | Project's secret server token.+newtype ProjectServerToken = ProjectServerToken T.Text deriving (Eq, Hashable, J.FromJSON, J.ToJSON)++-- | Size of a team in match request.+type MatchTeamSize = Int++-- | Match tag in match request.+newtype MatchTag = MatchTag T.Text deriving (Eq, Hashable, Monoid, J.FromJSON, J.ToJSON)++-- | Opaque player info.+newtype MatchPlayerInfo = MatchPlayerInfo T.Text deriving (Monoid, J.FromJSON, J.ToJSON)++-- | Match token.+data MatchToken = MatchToken+	{ matchToken_projectId :: {-# UNPACK #-} !ProjectId+	, matchToken_client :: !Client+	} deriving Generic+instance J.FromJSON MatchToken where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON MatchToken where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++-- | Session token.+data SessionToken = SessionToken+	{ sessionToken_sessionId :: !SessionId+	, sessionToken_teamIndex :: {-# UNPACK #-} !Int+	, sessionToken_mateIndex :: {-# UNPACK #-} !Int+	, sessionToken_client :: !Client+	} deriving Generic+instance J.FromJSON SessionToken where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON SessionToken where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++-- | Session id.+newtype SessionId = SessionId Base64ByteString deriving (Eq, Hashable, J.FromJSON, J.ToJSON)++-- | Server session token.+newtype ServerSessionToken = ServerSessionToken+	{ serverSessionToken_sessionId :: SessionId+	} deriving Generic+instance J.FromJSON ServerSessionToken where+	parseJSON = J.genericParseJSON jsonOptions+instance J.ToJSON ServerSessionToken where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++-- | Generic data type for id + object.+data Identified i a = Identified+	{ identified_id :: !i+	, identified_info :: !a+	} deriving Generic+instance (J.FromJSON i, J.FromJSON a) => J.FromJSON (Identified i a) where+	parseJSON = J.genericParseJSON jsonOptions+instance (J.ToJSON i, J.ToJSON a) => J.ToJSON (Identified i a) where+	toJSON = J.genericToJSON jsonOptions+	toEncoding = J.genericToEncoding jsonOptions++-- | Implementation for parseJson using base64-serialized string.+base64ParseJsonStr :: S.Serialize a => T.Text -> J.Parser a+base64ParseJsonStr = \case+	(BA.convertFromBase BA.Base64URLUnpadded . T.encodeUtf8 -> Right (S.decode -> Right object)) -> return object+	_ -> fail "wrong base64 object"++-- | Implementation for toJson using base64-serialized string.+base64ToJsonStr :: S.Serialize a => a -> T.Text+base64ToJsonStr = T.decodeUtf8 . BA.convertToBase BA.Base64URLUnpadded . S.encode++-- | Implementation for parseUrlPiece using base64-serialized string.+base64ParseUrlPiece :: S.Serialize a => T.Text -> Either T.Text a+base64ParseUrlPiece = either (Left . T.pack) (either (Left . T.pack) Right . S.decode) . BA.convertFromBase BA.Base64URLUnpadded . T.encodeUtf8++-- | ByteString which serializes to JSON as base64 string.+newtype Base64ByteString = Base64ByteString B.ByteString deriving (Eq, Ord, Monoid, Hashable, BA.ByteArray, BA.ByteArrayAccess)+instance J.FromJSON Base64ByteString where+	parseJSON = either fail return . BA.convertFromBase BA.Base64URLUnpadded . T.encodeUtf8 <=< J.parseJSON+instance J.ToJSON Base64ByteString where+	toJSON = J.toJSON . T.decodeUtf8 . BA.convertToBase BA.Base64URLUnpadded++-- | Word64 which serializes to JSON as base64 string.+-- Useful because 64-bit integer is not representable in javascript.+newtype Base64Word64 = Base64Word64 Word64 deriving (Eq, Ord, Num, Storable, Hashable, S.Serialize, Read, Show)+instance J.FromJSON Base64Word64 where+	parseJSON = base64ParseJsonStr <=< J.parseJSON+instance J.FromJSONKey Base64Word64 where+	fromJSONKey = J.FromJSONKeyTextParser base64ParseJsonStr+instance J.ToJSON Base64Word64 where+	toJSON = J.toJSON . base64ToJsonStr+	toEncoding = J.toEncoding . base64ToJsonStr+instance J.ToJSONKey Base64Word64 where+	toJSONKey = J.toJSONKeyText base64ToJsonStr+instance FromHttpApiData Base64Word64 where+	parseUrlPiece = base64ParseUrlPiece+instance IsString Base64Word64 where+	fromString = fromRight (error "wrong base64 word") . J.parseEither J.parseJSON . J.String . T.pack++-- | Word64 which serializes to JSON as decimal string.+-- Useful because 64-bit integer is not representable in javascript.+newtype StrWord64 = StrWord64 Word64 deriving (Eq, Ord, Num, Storable, Hashable, S.Serialize, Read, Show)+instance J.FromJSON StrWord64 where+	parseJSON = f . reads <=< J.parseJSON where+		f = \case+			[(n, "")] -> return $ StrWord64 n+			_ -> fail "wrong number"+instance J.ToJSON StrWord64 where+	toJSON (StrWord64 n) = J.toJSON $ show n+instance FromHttpApiData StrWord64 where+	parseUrlPiece = f . reads <=< parseUrlPiece where+		f = \case+			[(n, "")] -> return $ StrWord64 n+			_ -> fail "wrong number"
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2017-2018 Alexander Bich (aka Quyse Lert)++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ battleplace.cabal view
@@ -0,0 +1,35 @@+name:                battleplace+version:             0.1.0.0+synopsis:            Core definitions for BattlePlace.io service+description:         Core definitions for BattlePlace.io service+license:             MIT+license-file:        LICENSE+author:              Alexander Bich <quyse0@gmail.com>+maintainer:          Alexander Bich <quyse0@gmail.com>+copyright:           (c) 2017-2018 Alexander Bich+category:            Game+stability:           experimental+build-type:          Simple+cabal-version:       >=1.10++library+  exposed-modules:+    BattlePlace.Util+    BattlePlace.Rating+    BattlePlace.Skill.Glicko.Types+    BattlePlace.Token.Types+    BattlePlace.WebApi+    BattlePlace.WebApi.Types+  other-modules:+  build-depends:+    aeson+    , base >= 4.5 && < 5+    , bytestring+    , cereal+    , data-default+    , hashable+    , memory+    , servant+    , text+    , vector+  default-language:    Haskell2010