\subsection{Cardano.BM.Data.Configuration}
\label{code:Cardano.BM.Data.Configuration}

Data structure to help parsing configuration files.

%if style == newcode
\begin{code}
{-# LANGUAGE CPP                 #-}
{-# LANGUAGE DeriveAnyClass      #-}
{-# LANGUAGE DeriveGeneric       #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RecordWildCards     #-}

module Cardano.BM.Data.Configuration
  (
    Representation (..)
  , Port
  , HostPort
  , Endpoint (..)
  , RemoteAddr (..)
  , RemoteAddrNamed (..)
  , parseRepresentation
  , readRepresentation
  )
  where

import           Control.Exception (throwIO)
import           Data.Aeson.Types (typeMismatch)
import           Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as BS
import qualified Data.HashMap.Strict as HM
import           Data.Text (Text, unpack)
import qualified Data.Set as Set
import           Data.Scientific (Scientific, toBoundedInteger)
import qualified Data.Vector as V
import           Data.Yaml
import           GHC.Generics

import           Cardano.BM.Data.BackendKind
import           Cardano.BM.Data.Output
import           Cardano.BM.Data.Severity
import           Cardano.BM.Data.Rotation

\end{code}
%endif

\subsubsection{Representation}\label{code:Representation}\index{Representation}\label{code:Port}\index{Port}
\begin{code}
type Port = Int
type HostPort = (String, Port)
newtype Endpoint = Endpoint HostPort
  deriving (Endpoint -> Endpoint -> Bool
(Endpoint -> Endpoint -> Bool)
-> (Endpoint -> Endpoint -> Bool) -> Eq Endpoint
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Endpoint -> Endpoint -> Bool
$c/= :: Endpoint -> Endpoint -> Bool
== :: Endpoint -> Endpoint -> Bool
$c== :: Endpoint -> Endpoint -> Bool
Eq, (forall x. Endpoint -> Rep Endpoint x)
-> (forall x. Rep Endpoint x -> Endpoint) -> Generic Endpoint
forall x. Rep Endpoint x -> Endpoint
forall x. Endpoint -> Rep Endpoint x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Endpoint x -> Endpoint
$cfrom :: forall x. Endpoint -> Rep Endpoint x
Generic, Int -> Endpoint -> ShowS
[Endpoint] -> ShowS
Endpoint -> String
(Int -> Endpoint -> ShowS)
-> (Endpoint -> String) -> ([Endpoint] -> ShowS) -> Show Endpoint
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Endpoint] -> ShowS
$cshowList :: [Endpoint] -> ShowS
show :: Endpoint -> String
$cshow :: Endpoint -> String
showsPrec :: Int -> Endpoint -> ShowS
$cshowsPrec :: Int -> Endpoint -> ShowS
Show, [Endpoint] -> Encoding
[Endpoint] -> Value
Endpoint -> Encoding
Endpoint -> Value
(Endpoint -> Value)
-> (Endpoint -> Encoding)
-> ([Endpoint] -> Value)
-> ([Endpoint] -> Encoding)
-> ToJSON Endpoint
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [Endpoint] -> Encoding
$ctoEncodingList :: [Endpoint] -> Encoding
toJSONList :: [Endpoint] -> Value
$ctoJSONList :: [Endpoint] -> Value
toEncoding :: Endpoint -> Encoding
$ctoEncoding :: Endpoint -> Encoding
toJSON :: Endpoint -> Value
$ctoJSON :: Endpoint -> Value
ToJSON)

-- It's possible to specify host and port for EKG or port only
-- (to keep backward compatibility with existing configurations).
-- For example:
--   hasEKG:
--     - "127.0.0.1"
--     - 12789
-- or
--   hasEKG: 12789
-- That's why we provide a custom FromJSON-instance for Endpoint.
instance FromJSON Endpoint where
  parseJSON :: Value -> Parser Endpoint
parseJSON o :: Value
o@(Array Array
a) =
    case Array -> [Value]
forall a. Vector a -> [a]
V.toList Array
a of
      [Value
h, Value
p] -> do
        Text
host <-
          case Value
h of
            String Text
s -> Text -> Parser Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
s
            Value
_ -> String -> Value -> Parser Text
forall a. String -> Value -> Parser a
typeMismatch String
"String" Value
h
        Int
port <-
          case Value
p of
            Number Scientific
n ->
              case Scientific -> Maybe Int
mkInt Scientific
n of
                Just Int
p' -> Int -> Parser Int
forall (m :: * -> *) a. Monad m => a -> m a
return Int
p'
                Maybe Int
Nothing -> String -> Value -> Parser Int
forall a. String -> Value -> Parser a
typeMismatch String
"Number" Value
p
            Value
_ -> String -> Value -> Parser Int
forall a. String -> Value -> Parser a
typeMismatch String
"Object" Value
p
        Endpoint -> Parser Endpoint
forall (m :: * -> *) a. Monad m => a -> m a
return (Endpoint -> Parser Endpoint) -> Endpoint -> Parser Endpoint
forall a b. (a -> b) -> a -> b
$ HostPort -> Endpoint
Endpoint (Text -> String
unpack Text
host, Int
port)
      [Value]
_ -> String -> Value -> Parser Endpoint
forall a. String -> Value -> Parser a
typeMismatch String
"Array" Value
o

  parseJSON o :: Value
o@(Number Scientific
n) =
    case Scientific -> Maybe Int
mkInt Scientific
n of
      Just Int
port -> Endpoint -> Parser Endpoint
forall (m :: * -> *) a. Monad m => a -> m a
return (Endpoint -> Parser Endpoint) -> Endpoint -> Parser Endpoint
forall a b. (a -> b) -> a -> b
$ HostPort -> Endpoint
Endpoint (String
"127.0.0.1", Int
port)
      Maybe Int
Nothing -> String -> Value -> Parser Endpoint
forall a. String -> Value -> Parser a
typeMismatch String
"Number" Value
o

  parseJSON Value
invalid =
    String -> Value -> Parser Endpoint
forall a. String -> Value -> Parser a
typeMismatch String
"Object" Value
invalid

mkInt :: Scientific -> Maybe Int
mkInt :: Scientific -> Maybe Int
mkInt = Scientific -> Maybe Int
forall i. (Integral i, Bounded i) => Scientific -> Maybe i
toBoundedInteger

data Representation = Representation
    { Representation -> Severity
minSeverity     :: Severity
    , Representation -> Maybe RotationParameters
rotation        :: Maybe RotationParameters
    , Representation -> [ScribeDefinition]
setupScribes    :: [ScribeDefinition]
    , Representation -> [(ScribeKind, Text)]
defaultScribes  :: [(ScribeKind,Text)]
    , Representation -> [BackendKind]
setupBackends   :: [BackendKind]
    , Representation -> [BackendKind]
defaultBackends :: [BackendKind]
    , Representation -> Maybe Endpoint
hasEKG          :: Maybe Endpoint
    , Representation -> Maybe Int
hasGraylog      :: Maybe Port
    , Representation -> Maybe HostPort
hasPrometheus   :: Maybe HostPort
    , Representation -> Maybe Int
hasGUI          :: Maybe Port
    , Representation -> Maybe RemoteAddr
traceForwardTo  :: Maybe RemoteAddr
    , Representation -> Maybe Word
forwardDelay    :: Maybe Word
    , Representation -> Maybe [RemoteAddrNamed]
traceAcceptAt   :: Maybe [RemoteAddrNamed]
    , Representation -> HashMap Text Value
options         :: HM.HashMap Text Value
    }
    deriving ((forall x. Representation -> Rep Representation x)
-> (forall x. Rep Representation x -> Representation)
-> Generic Representation
forall x. Rep Representation x -> Representation
forall x. Representation -> Rep Representation x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Representation x -> Representation
$cfrom :: forall x. Representation -> Rep Representation x
Generic, Int -> Representation -> ShowS
[Representation] -> ShowS
Representation -> String
(Int -> Representation -> ShowS)
-> (Representation -> String)
-> ([Representation] -> ShowS)
-> Show Representation
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Representation] -> ShowS
$cshowList :: [Representation] -> ShowS
show :: Representation -> String
$cshow :: Representation -> String
showsPrec :: Int -> Representation -> ShowS
$cshowsPrec :: Int -> Representation -> ShowS
Show, [Representation] -> Encoding
[Representation] -> Value
Representation -> Encoding
Representation -> Value
(Representation -> Value)
-> (Representation -> Encoding)
-> ([Representation] -> Value)
-> ([Representation] -> Encoding)
-> ToJSON Representation
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [Representation] -> Encoding
$ctoEncodingList :: [Representation] -> Encoding
toJSONList :: [Representation] -> Value
$ctoJSONList :: [Representation] -> Value
toEncoding :: Representation -> Encoding
$ctoEncoding :: Representation -> Encoding
toJSON :: Representation -> Value
$ctoJSON :: Representation -> Value
ToJSON, Value -> Parser [Representation]
Value -> Parser Representation
(Value -> Parser Representation)
-> (Value -> Parser [Representation]) -> FromJSON Representation
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [Representation]
$cparseJSONList :: Value -> Parser [Representation]
parseJSON :: Value -> Parser Representation
$cparseJSON :: Value -> Parser Representation
FromJSON)

data RemoteAddr
  = RemotePipe FilePath
  | RemoteSocket String String
  deriving ((forall x. RemoteAddr -> Rep RemoteAddr x)
-> (forall x. Rep RemoteAddr x -> RemoteAddr) -> Generic RemoteAddr
forall x. Rep RemoteAddr x -> RemoteAddr
forall x. RemoteAddr -> Rep RemoteAddr x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep RemoteAddr x -> RemoteAddr
$cfrom :: forall x. RemoteAddr -> Rep RemoteAddr x
Generic, RemoteAddr -> RemoteAddr -> Bool
(RemoteAddr -> RemoteAddr -> Bool)
-> (RemoteAddr -> RemoteAddr -> Bool) -> Eq RemoteAddr
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RemoteAddr -> RemoteAddr -> Bool
$c/= :: RemoteAddr -> RemoteAddr -> Bool
== :: RemoteAddr -> RemoteAddr -> Bool
$c== :: RemoteAddr -> RemoteAddr -> Bool
Eq, Int -> RemoteAddr -> ShowS
[RemoteAddr] -> ShowS
RemoteAddr -> String
(Int -> RemoteAddr -> ShowS)
-> (RemoteAddr -> String)
-> ([RemoteAddr] -> ShowS)
-> Show RemoteAddr
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RemoteAddr] -> ShowS
$cshowList :: [RemoteAddr] -> ShowS
show :: RemoteAddr -> String
$cshow :: RemoteAddr -> String
showsPrec :: Int -> RemoteAddr -> ShowS
$cshowsPrec :: Int -> RemoteAddr -> ShowS
Show, [RemoteAddr] -> Encoding
[RemoteAddr] -> Value
RemoteAddr -> Encoding
RemoteAddr -> Value
(RemoteAddr -> Value)
-> (RemoteAddr -> Encoding)
-> ([RemoteAddr] -> Value)
-> ([RemoteAddr] -> Encoding)
-> ToJSON RemoteAddr
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [RemoteAddr] -> Encoding
$ctoEncodingList :: [RemoteAddr] -> Encoding
toJSONList :: [RemoteAddr] -> Value
$ctoJSONList :: [RemoteAddr] -> Value
toEncoding :: RemoteAddr -> Encoding
$ctoEncoding :: RemoteAddr -> Encoding
toJSON :: RemoteAddr -> Value
$ctoJSON :: RemoteAddr -> Value
ToJSON, Value -> Parser [RemoteAddr]
Value -> Parser RemoteAddr
(Value -> Parser RemoteAddr)
-> (Value -> Parser [RemoteAddr]) -> FromJSON RemoteAddr
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [RemoteAddr]
$cparseJSONList :: Value -> Parser [RemoteAddr]
parseJSON :: Value -> Parser RemoteAddr
$cparseJSON :: Value -> Parser RemoteAddr
FromJSON)

data RemoteAddrNamed = RemoteAddrNamed
  { RemoteAddrNamed -> Text
nodeName   :: Text
  , RemoteAddrNamed -> RemoteAddr
remoteAddr :: RemoteAddr
  } deriving ((forall x. RemoteAddrNamed -> Rep RemoteAddrNamed x)
-> (forall x. Rep RemoteAddrNamed x -> RemoteAddrNamed)
-> Generic RemoteAddrNamed
forall x. Rep RemoteAddrNamed x -> RemoteAddrNamed
forall x. RemoteAddrNamed -> Rep RemoteAddrNamed x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep RemoteAddrNamed x -> RemoteAddrNamed
$cfrom :: forall x. RemoteAddrNamed -> Rep RemoteAddrNamed x
Generic, RemoteAddrNamed -> RemoteAddrNamed -> Bool
(RemoteAddrNamed -> RemoteAddrNamed -> Bool)
-> (RemoteAddrNamed -> RemoteAddrNamed -> Bool)
-> Eq RemoteAddrNamed
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RemoteAddrNamed -> RemoteAddrNamed -> Bool
$c/= :: RemoteAddrNamed -> RemoteAddrNamed -> Bool
== :: RemoteAddrNamed -> RemoteAddrNamed -> Bool
$c== :: RemoteAddrNamed -> RemoteAddrNamed -> Bool
Eq, Int -> RemoteAddrNamed -> ShowS
[RemoteAddrNamed] -> ShowS
RemoteAddrNamed -> String
(Int -> RemoteAddrNamed -> ShowS)
-> (RemoteAddrNamed -> String)
-> ([RemoteAddrNamed] -> ShowS)
-> Show RemoteAddrNamed
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RemoteAddrNamed] -> ShowS
$cshowList :: [RemoteAddrNamed] -> ShowS
show :: RemoteAddrNamed -> String
$cshow :: RemoteAddrNamed -> String
showsPrec :: Int -> RemoteAddrNamed -> ShowS
$cshowsPrec :: Int -> RemoteAddrNamed -> ShowS
Show, [RemoteAddrNamed] -> Encoding
[RemoteAddrNamed] -> Value
RemoteAddrNamed -> Encoding
RemoteAddrNamed -> Value
(RemoteAddrNamed -> Value)
-> (RemoteAddrNamed -> Encoding)
-> ([RemoteAddrNamed] -> Value)
-> ([RemoteAddrNamed] -> Encoding)
-> ToJSON RemoteAddrNamed
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [RemoteAddrNamed] -> Encoding
$ctoEncodingList :: [RemoteAddrNamed] -> Encoding
toJSONList :: [RemoteAddrNamed] -> Value
$ctoJSONList :: [RemoteAddrNamed] -> Value
toEncoding :: RemoteAddrNamed -> Encoding
$ctoEncoding :: RemoteAddrNamed -> Encoding
toJSON :: RemoteAddrNamed -> Value
$ctoJSON :: RemoteAddrNamed -> Value
ToJSON, Value -> Parser [RemoteAddrNamed]
Value -> Parser RemoteAddrNamed
(Value -> Parser RemoteAddrNamed)
-> (Value -> Parser [RemoteAddrNamed]) -> FromJSON RemoteAddrNamed
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [RemoteAddrNamed]
$cparseJSONList :: Value -> Parser [RemoteAddrNamed]
parseJSON :: Value -> Parser RemoteAddrNamed
$cparseJSON :: Value -> Parser RemoteAddrNamed
FromJSON)

\end{code}

\subsubsection{readRepresentation}\label{code:readRepresentation}\index{readRepresentation}
\begin{code}
readRepresentation :: FilePath -> IO Representation
readRepresentation :: String -> IO Representation
readRepresentation String
fp =
    (ParseException -> IO Representation)
-> (Representation -> IO Representation)
-> Either ParseException Representation
-> IO Representation
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ParseException -> IO Representation
forall e a. Exception e => e -> IO a
throwIO Representation -> IO Representation
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either ParseException Representation -> IO Representation)
-> IO (Either ParseException Representation) -> IO Representation
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ByteString -> Either ParseException Representation
parseRepresentation (ByteString -> Either ParseException Representation)
-> IO ByteString -> IO (Either ParseException Representation)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO ByteString
BS.readFile String
fp

\end{code}

\subsubsection{parseRepresentation}\label{code:parseRepresentation}\index{parseRepresentation}
\begin{code}
parseRepresentation :: ByteString -> Either ParseException Representation
parseRepresentation :: ByteString -> Either ParseException Representation
parseRepresentation =
    (Representation -> Representation)
-> Either ParseException Representation
-> Either ParseException Representation
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Representation -> Representation
implicit_fill_representation (Either ParseException Representation
 -> Either ParseException Representation)
-> (ByteString -> Either ParseException Representation)
-> ByteString
-> Either ParseException Representation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either ParseException Representation
forall a. FromJSON a => ByteString -> Either ParseException a
decodeEither'

\end{code}


after parsing the configuration representation we implicitly correct it.
\begin{code}
implicit_fill_representation :: Representation -> Representation
implicit_fill_representation :: Representation -> Representation
implicit_fill_representation =
    Representation -> Representation
remove_ekgview_if_not_defined (Representation -> Representation)
-> (Representation -> Representation)
-> Representation
-> Representation
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Representation -> Representation
filter_duplicates_from_backends (Representation -> Representation)
-> (Representation -> Representation)
-> Representation
-> Representation
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Representation -> Representation
filter_duplicates_from_scribes (Representation -> Representation)
-> (Representation -> Representation)
-> Representation
-> Representation
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Representation -> Representation
union_setup_and_usage_backends (Representation -> Representation)
-> (Representation -> Representation)
-> Representation
-> Representation
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Representation -> Representation
add_ekgview_if_port_defined (Representation -> Representation)
-> (Representation -> Representation)
-> Representation
-> Representation
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Representation -> Representation
add_katip_if_any_scribes
  where
    filter_duplicates_from_backends :: Representation -> Representation
filter_duplicates_from_backends Representation
r =
        Representation
r {setupBackends :: [BackendKind]
setupBackends = [BackendKind] -> [BackendKind]
forall a. Ord a => [a] -> [a]
mkUniq ([BackendKind] -> [BackendKind]) -> [BackendKind] -> [BackendKind]
forall a b. (a -> b) -> a -> b
$ Representation -> [BackendKind]
setupBackends Representation
r}
    filter_duplicates_from_scribes :: Representation -> Representation
filter_duplicates_from_scribes Representation
r =
        Representation
r {setupScribes :: [ScribeDefinition]
setupScribes = [ScribeDefinition] -> [ScribeDefinition]
forall a. Ord a => [a] -> [a]
mkUniq ([ScribeDefinition] -> [ScribeDefinition])
-> [ScribeDefinition] -> [ScribeDefinition]
forall a b. (a -> b) -> a -> b
$ Representation -> [ScribeDefinition]
setupScribes Representation
r}
    union_setup_and_usage_backends :: Representation -> Representation
union_setup_and_usage_backends Representation
r =
        Representation
r {setupBackends :: [BackendKind]
setupBackends = Representation -> [BackendKind]
setupBackends Representation
r [BackendKind] -> [BackendKind] -> [BackendKind]
forall a. Semigroup a => a -> a -> a
<> Representation -> [BackendKind]
defaultBackends Representation
r}
    remove_ekgview_if_not_defined :: Representation -> Representation
remove_ekgview_if_not_defined Representation
r =
        case Representation -> Maybe Endpoint
hasEKG Representation
r of
        Maybe Endpoint
Nothing -> Representation
r { defaultBackends :: [BackendKind]
defaultBackends = (BackendKind -> Bool) -> [BackendKind] -> [BackendKind]
forall a. (a -> Bool) -> [a] -> [a]
filter (\BackendKind
bk -> BackendKind
bk BackendKind -> BackendKind -> Bool
forall a. Eq a => a -> a -> Bool
/= BackendKind
EKGViewBK) (Representation -> [BackendKind]
defaultBackends Representation
r)
                     , setupBackends :: [BackendKind]
setupBackends = (BackendKind -> Bool) -> [BackendKind] -> [BackendKind]
forall a. (a -> Bool) -> [a] -> [a]
filter (\BackendKind
bk -> BackendKind
bk BackendKind -> BackendKind -> Bool
forall a. Eq a => a -> a -> Bool
/= BackendKind
EKGViewBK) (Representation -> [BackendKind]
setupBackends Representation
r)
                     }
        Just Endpoint
_  -> Representation
r
    add_ekgview_if_port_defined :: Representation -> Representation
add_ekgview_if_port_defined Representation
r =
        case Representation -> Maybe Endpoint
hasEKG Representation
r of
        Maybe Endpoint
Nothing -> Representation
r
        Just Endpoint
_  -> Representation
r {setupBackends :: [BackendKind]
setupBackends = Representation -> [BackendKind]
setupBackends Representation
r [BackendKind] -> [BackendKind] -> [BackendKind]
forall a. Semigroup a => a -> a -> a
<> [BackendKind
EKGViewBK]}
    add_katip_if_any_scribes :: Representation -> Representation
add_katip_if_any_scribes Representation
r =
        if ((Bool -> Bool) -> [Bool] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Bool -> Bool
not [[ScribeDefinition] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([ScribeDefinition] -> Bool) -> [ScribeDefinition] -> Bool
forall a b. (a -> b) -> a -> b
$ Representation -> [ScribeDefinition]
setupScribes Representation
r, [(ScribeKind, Text)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([(ScribeKind, Text)] -> Bool) -> [(ScribeKind, Text)] -> Bool
forall a b. (a -> b) -> a -> b
$ Representation -> [(ScribeKind, Text)]
defaultScribes Representation
r])
        then Representation
r {setupBackends :: [BackendKind]
setupBackends = Representation -> [BackendKind]
setupBackends Representation
r [BackendKind] -> [BackendKind] -> [BackendKind]
forall a. Semigroup a => a -> a -> a
<> [BackendKind
KatipBK]}
        else Representation
r
    mkUniq :: Ord a => [a] -> [a]
    mkUniq :: [a] -> [a]
mkUniq = Set a -> [a]
forall a. Set a -> [a]
Set.toList (Set a -> [a]) -> ([a] -> Set a) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Set a
forall a. Ord a => [a] -> Set a
Set.fromList

\end{code}