    --------------------------------------------------------------------------------
    -- | This module containing some specialized functions to deal with tags. It
    -- assumes you follow some conventions.
    --
    -- We support two types of tags: tags and categories.
    --
    -- To use default tags, use 'buildTags'. Tags are placed in a comma-separated
    -- metadata field like this:
    --
    -- > ---
    -- > author: Philip K. Dick
    -- > title: Do androids dream of electric sheep?
    -- > tags: future, science fiction, humanoid
    -- > ---
    -- > The novel is set in a post-apocalyptic near future, where the Earth and
    -- > its populations have been damaged greatly by Nuclear...
    --
    -- To use categories, use the 'buildCategories' function. Categories are
    -- determined by the directory a page is in, for example, the post
    --
    -- > posts/coding/2010-01-28-hakyll-categories.markdown
    --
    -- will receive the @coding@ category.
    --
    -- Advanced users may implement custom systems using 'buildTagsWith' if desired.
    --
    -- In the above example, we would want to create a page which lists all pages in
    -- the @coding@ category, for example, with the 'Identifier':
    --
    -- > tags/coding.html
    --
    -- This is where the first parameter of 'buildTags' and 'buildCategories' comes
    -- in. In the above case, we used the function:
    --
    -- > fromCapture "tags/*.html" :: String -> Identifier
    --
    -- The 'tagsRules' function lets you generate such a page for each tag in the
    -- 'Rules' monad.
    {-# LANGUAGE Arrows                     #-}
    {-# LANGUAGE DeriveDataTypeable         #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    {-# LANGUAGE OverloadedStrings          #-}
    module Hakyll.Web.Tags
        ( Tags (..)
        , getTags
        , getTagsByField
        , getCategory
        , buildTagsWith
        , buildTags
        , buildCategories
        , tagsRules
        , renderTags
        , renderTagCloud
        , renderTagCloudWith
        , tagCloudField
        , tagCloudFieldWith
        , renderTagList
        , tagsField
        , tagsFieldWith
        , categoryField
        , simpleRenderLink
        , sortTagsBy
        , caseInsensitiveTags
        ) where

    --------------------------------------------------------------------------------
    import           Control.Arrow                   ((&&&))
    import           Control.Monad                   (foldM, forM, forM_, mplus)
    import           Data.Char                       (toLower)
    import           Data.List                       (intercalate, intersperse,
                                                      sortBy)
    import qualified Data.Map                        as M
    import           Data.Maybe                      (catMaybes, fromMaybe)
    import           Data.Ord                        (comparing)
    import qualified Data.Set                        as S
    import           System.FilePath                 (takeBaseName, takeDirectory)
    import           Text.Blaze.Html                 (toHtml, toValue, (!))
    import           Text.Blaze.Html.Renderer.String (renderHtml)
    import qualified Text.Blaze.Html5                as H
    import qualified Text.Blaze.Html5.Attributes     as A

    --------------------------------------------------------------------------------
    import           Hakyll.Core.Compiler
    import           Hakyll.Core.Dependencies
    import           Hakyll.Core.Identifier
    import           Hakyll.Core.Identifier.Pattern
    import           Hakyll.Core.Item
    import           Hakyll.Core.Metadata
    import           Hakyll.Core.Rules
    import           Hakyll.Core.Util.String
    import           Hakyll.Web.Html
    import           Hakyll.Web.Template.Context

    --------------------------------------------------------------------------------
    -- | Data about tags
    data Tags = Tags
        { Tags -> [([Char], [Identifier])]
    tagsMap        :: [(String, [Identifier])]
        , Tags -> [Char] -> Identifier
    tagsMakeId     :: String -> Identifier
        , Tags -> Dependency
    tagsDependency :: Dependency
        }

    --------------------------------------------------------------------------------
    -- | Obtain tags from a page in the default way: parse them from the @tags@
    -- metadata field. This can either be a list or a comma-separated string.
    getTags :: MonadMetadata m => Identifier -> m [String]
    getTags :: forall (m :: * -> *). MonadMetadata m => Identifier -> m [[Char]]
    getTags = [Char] -> Identifier -> m [[Char]]
    forall (m :: * -> *).
    MonadMetadata m =>
    [Char] -> Identifier -> m [[Char]]
    getTagsByField [Char]
    "tags"

    -- | Obtain tags from a page by name of the metadata field. These can be a list
    -- or a comma-separated string
    getTagsByField :: MonadMetadata m => String -> Identifier -> m [String]
    getTagsByField :: forall (m :: * -> *).
    MonadMetadata m =>
    [Char] -> Identifier -> m [[Char]]
    getTagsByField [Char]
    fieldName Identifier
    identifier = do
        Metadata
    metadata <- Identifier -> m Metadata
    forall (m :: * -> *). MonadMetadata m => Identifier -> m Metadata
    getMetadata Identifier
    identifier
        [[Char]] -> m [[Char]]
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([[Char]] -> m [[Char]]) -> [[Char]] -> m [[Char]]
    forall a b. (a -> b) -> a -> b
    $ [[Char]] -> Maybe [[Char]] -> [[Char]]
    forall a. a -> Maybe a -> a
    fromMaybe [] (Maybe [[Char]] -> [[Char]]) -> Maybe [[Char]] -> [[Char]]
    forall a b. (a -> b) -> a -> b
    $
            ([Char] -> Metadata -> Maybe [[Char]]
    lookupStringList [Char]
    fieldName Metadata
    metadata) Maybe [[Char]] -> Maybe [[Char]] -> Maybe [[Char]]
    forall a. Maybe a -> Maybe a -> Maybe a
    forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
    `mplus`
            (([Char] -> [Char]) -> [[Char]] -> [[Char]]
    forall a b. (a -> b) -> [a] -> [b]
    map [Char] -> [Char]
    trim ([[Char]] -> [[Char]])
    -> ([Char] -> [[Char]]) -> [Char] -> [[Char]]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Char] -> [Char] -> [[Char]]
    splitAll [Char]
    "," ([Char] -> [[Char]]) -> Maybe [Char] -> Maybe [[Char]]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> [Char] -> Metadata -> Maybe [Char]
    lookupString [Char]
    fieldName Metadata
    metadata)

    --------------------------------------------------------------------------------
    -- | Obtain category from a page.
    getCategory :: MonadMetadata m => Identifier -> m [String]
    getCategory :: forall (m :: * -> *). MonadMetadata m => Identifier -> m [[Char]]
    getCategory = [[Char]] -> m [[Char]]
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([[Char]] -> m [[Char]])
    -> (Identifier -> [[Char]]) -> Identifier -> m [[Char]]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Char] -> [[Char]]
    forall a. a -> [a]
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Char] -> [[Char]])
    -> (Identifier -> [Char]) -> Identifier -> [[Char]]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Char] -> [Char]
    takeBaseName ([Char] -> [Char])
    -> (Identifier -> [Char]) -> Identifier -> [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Char] -> [Char]
    takeDirectory ([Char] -> [Char])
    -> (Identifier -> [Char]) -> Identifier -> [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Identifier -> [Char]
    toFilePath

    --------------------------------------------------------------------------------
    -- | Higher-order function to read tags
    buildTagsWith :: MonadMetadata m
                  => (Identifier -> m [String])
                  -> Pattern
                  -> (String -> Identifier)
                  -> m Tags
    buildTagsWith :: forall (m :: * -> *).
    MonadMetadata m =>
    (Identifier -> m [[Char]])
    -> Pattern -> ([Char] -> Identifier) -> m Tags
    buildTagsWith Identifier -> m [[Char]]
    f Pattern
    pattern [Char] -> Identifier
    makeId = do
        [Identifier]
    ids    <- Pattern -> m [Identifier]
    forall (m :: * -> *). MonadMetadata m => Pattern -> m [Identifier]
    getMatches Pattern
    pattern
        Map [Char] [Identifier]
    tagMap <- (Map [Char] [Identifier]
     -> Identifier -> m (Map [Char] [Identifier]))
    -> Map [Char] [Identifier]
    -> [Identifier]
    -> m (Map [Char] [Identifier])
    forall (t :: * -> *) (m :: * -> *) b a.
    (Foldable t, Monad m) =>
    (b -> a -> m b) -> b -> t a -> m b
    foldM Map [Char] [Identifier]
    -> Identifier -> m (Map [Char] [Identifier])
    addTags Map [Char] [Identifier]
    forall k a. Map k a
    M.empty [Identifier]
    ids
        let set' :: Set Identifier
    set' = [Identifier] -> Set Identifier
    forall a. Ord a => [a] -> Set a
    S.fromList [Identifier]
    ids
        Tags -> m Tags
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Tags -> m Tags) -> Tags -> m Tags
    forall a b. (a -> b) -> a -> b
    $ [([Char], [Identifier])]
    -> ([Char] -> Identifier) -> Dependency -> Tags
    Tags (Map [Char] [Identifier] -> [([Char], [Identifier])]
    forall k a. Map k a -> [(k, a)]
    M.toList Map [Char] [Identifier]
    tagMap) [Char] -> Identifier
    makeId (Pattern -> Set Identifier -> Dependency
    PatternDependency Pattern
    pattern Set Identifier
    set')
      where
        -- Create a tag map for one page
        addTags :: Map [Char] [Identifier]
    -> Identifier -> m (Map [Char] [Identifier])
    addTags Map [Char] [Identifier]
    tagMap Identifier
    id' = do
            [[Char]]
    tags <- Identifier -> m [[Char]]
    f Identifier
    id'
            let tagMap' :: Map [Char] [Identifier]
    tagMap' = [([Char], [Identifier])] -> Map [Char] [Identifier]
    forall k a. Ord k => [(k, a)] -> Map k a
    M.fromList ([([Char], [Identifier])] -> Map [Char] [Identifier])
    -> [([Char], [Identifier])] -> Map [Char] [Identifier]
    forall a b. (a -> b) -> a -> b
    $ [[Char]] -> [[Identifier]] -> [([Char], [Identifier])]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [[Char]]
    tags ([[Identifier]] -> [([Char], [Identifier])])
    -> [[Identifier]] -> [([Char], [Identifier])]
    forall a b. (a -> b) -> a -> b
    $ [Identifier] -> [[Identifier]]
    forall a. a -> [a]
    repeat [Identifier
    id']
            Map [Char] [Identifier] -> m (Map [Char] [Identifier])
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Map [Char] [Identifier] -> m (Map [Char] [Identifier]))
    -> Map [Char] [Identifier] -> m (Map [Char] [Identifier])
    forall a b. (a -> b) -> a -> b
    $ ([Identifier] -> [Identifier] -> [Identifier])
    -> Map [Char] [Identifier]
    -> Map [Char] [Identifier]
    -> Map [Char] [Identifier]
    forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
    M.unionWith [Identifier] -> [Identifier] -> [Identifier]
    forall a. [a] -> [a] -> [a]
    (++) Map [Char] [Identifier]
    tagMap Map [Char] [Identifier]
    tagMap'

    --------------------------------------------------------------------------------
    buildTags :: MonadMetadata m => Pattern -> (String -> Identifier) -> m Tags
    buildTags :: forall (m :: * -> *).
    MonadMetadata m =>
    Pattern -> ([Char] -> Identifier) -> m Tags
    buildTags = (Identifier -> m [[Char]])
    -> Pattern -> ([Char] -> Identifier) -> m Tags
    forall (m :: * -> *).
    MonadMetadata m =>
    (Identifier -> m [[Char]])
    -> Pattern -> ([Char] -> Identifier) -> m Tags
    buildTagsWith Identifier -> m [[Char]]
    forall (m :: * -> *). MonadMetadata m => Identifier -> m [[Char]]
    getTags

    --------------------------------------------------------------------------------
    buildCategories :: MonadMetadata m => Pattern -> (String -> Identifier)
                    -> m Tags
    buildCategories :: forall (m :: * -> *).
    MonadMetadata m =>
    Pattern -> ([Char] -> Identifier) -> m Tags
    buildCategories = (Identifier -> m [[Char]])
    -> Pattern -> ([Char] -> Identifier) -> m Tags
    forall (m :: * -> *).
    MonadMetadata m =>
    (Identifier -> m [[Char]])
    -> Pattern -> ([Char] -> Identifier) -> m Tags
    buildTagsWith Identifier -> m [[Char]]
    forall (m :: * -> *). MonadMetadata m => Identifier -> m [[Char]]
    getCategory

    --------------------------------------------------------------------------------
    tagsRules :: Tags -> (String -> Pattern -> Rules ()) -> Rules ()
    tagsRules :: Tags -> ([Char] -> Pattern -> Rules ()) -> Rules ()
    tagsRules Tags
    tags [Char] -> Pattern -> Rules ()
    rules =
        [([Char], [Identifier])]
    -> (([Char], [Identifier]) -> Rules ()) -> Rules ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    t a -> (a -> m b) -> m ()
    forM_ (Tags -> [([Char], [Identifier])]
    tagsMap Tags
    tags) ((([Char], [Identifier]) -> Rules ()) -> Rules ())
    -> (([Char], [Identifier]) -> Rules ()) -> Rules ()
    forall a b. (a -> b) -> a -> b
    $ \([Char]
    tag, [Identifier]
    identifiers) ->
            [Dependency] -> Rules () -> Rules ()
    forall a. [Dependency] -> Rules a -> Rules a
    rulesExtraDependencies [Tags -> Dependency
    tagsDependency Tags
    tags] (Rules () -> Rules ()) -> Rules () -> Rules ()
    forall a b. (a -> b) -> a -> b
    $
                [Identifier] -> Rules () -> Rules ()
    create [Tags -> [Char] -> Identifier
    tagsMakeId Tags
    tags [Char]
    tag] (Rules () -> Rules ()) -> Rules () -> Rules ()
    forall a b. (a -> b) -> a -> b
    $
                    [Char] -> Pattern -> Rules ()
    rules [Char]
    tag (Pattern -> Rules ()) -> Pattern -> Rules ()
    forall a b. (a -> b) -> a -> b
    $ [Identifier] -> Pattern
    fromList [Identifier]
    identifiers

    --------------------------------------------------------------------------------
    -- | Render tags in HTML (the flexible higher-order function)
    renderTags :: (String -> String -> Int -> Int -> Int -> String)
               -- ^ Produce a tag item: tag, url, count, min count, max count
               -> ([String] -> String)
               -- ^ Join items
               -> Tags
               -- ^ Tag cloud renderer
               -> Compiler String
    renderTags :: ([Char] -> [Char] -> Int -> Int -> Int -> [Char])
    -> ([[Char]] -> [Char]) -> Tags -> Compiler [Char]
    renderTags [Char] -> [Char] -> Int -> Int -> Int -> [Char]
    makeHtml [[Char]] -> [Char]
    concatHtml Tags
    tags = do
        -- In tags' we create a list: [((tag, route), count)]
        [(([Char], Maybe [Char]), Int)]
    tags' <- [([Char], [Identifier])]
    -> (([Char], [Identifier])
        -> Compiler (([Char], Maybe [Char]), Int))
    -> Compiler [(([Char], Maybe [Char]), Int)]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    t a -> (a -> m b) -> m (t b)
    forM (Tags -> [([Char], [Identifier])]
    tagsMap Tags
    tags) ((([Char], [Identifier]) -> Compiler (([Char], Maybe [Char]), Int))
     -> Compiler [(([Char], Maybe [Char]), Int)])
    -> (([Char], [Identifier])
        -> Compiler (([Char], Maybe [Char]), Int))
    -> Compiler [(([Char], Maybe [Char]), Int)]
    forall a b. (a -> b) -> a -> b
    $ \([Char]
    tag, [Identifier]
    ids) -> do
            Maybe [Char]
    route' <- Identifier -> Compiler (Maybe [Char])
    getRoute (Identifier -> Compiler (Maybe [Char]))
    -> Identifier -> Compiler (Maybe [Char])
    forall a b. (a -> b) -> a -> b
    $ Tags -> [Char] -> Identifier
    tagsMakeId Tags
    tags [Char]
    tag
            (([Char], Maybe [Char]), Int)
    -> Compiler (([Char], Maybe [Char]), Int)
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (([Char]
    tag, Maybe [Char]
    route'), [Identifier] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [Identifier]
    ids)

        -- TODO: We actually need to tell a dependency here!

        let -- Absolute frequencies of the pages
            freqs :: [Int]
    freqs = ((([Char], Maybe [Char]), Int) -> Int)
    -> [(([Char], Maybe [Char]), Int)] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map (([Char], Maybe [Char]), Int) -> Int
    forall a b. (a, b) -> b
    snd [(([Char], Maybe [Char]), Int)]
    tags'

            -- The minimum and maximum count found
            (Int
    min', Int
    max')
                | [Int] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [Int]
    freqs = (Int
    0, Int
    1)
                | Bool
    otherwise  = ([Int] -> Int
    forall a. Ord a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    minimum ([Int] -> Int) -> ([Int] -> Int) -> [Int] -> (Int, Int)
    forall b c c'. (b -> c) -> (b -> c') -> b -> (c, c')
    forall (a :: * -> * -> *) b c c'.
    Arrow a =>
    a b c -> a b c' -> a b (c, c')
    &&& [Int] -> Int
    forall a. Ord a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    maximum) [Int]
    freqs

            -- Create a link for one item
            makeHtml' :: (([Char], Maybe [Char]), Int) -> [Char]
    makeHtml' (([Char]
    tag, Maybe [Char]
    url), Int
    count) =
                [Char] -> [Char] -> Int -> Int -> Int -> [Char]
    makeHtml [Char]
    tag ([Char] -> [Char]
    toUrl ([Char] -> [Char]) -> [Char] -> [Char]
    forall a b. (a -> b) -> a -> b
    $ [Char] -> Maybe [Char] -> [Char]
    forall a. a -> Maybe a -> a
    fromMaybe [Char]
    "/" Maybe [Char]
    url) Int
    count Int
    min' Int
    max'

        -- Render and return the HTML
        [Char] -> Compiler [Char]
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Char] -> Compiler [Char]) -> [Char] -> Compiler [Char]
    forall a b. (a -> b) -> a -> b
    $ [[Char]] -> [Char]
    concatHtml ([[Char]] -> [Char]) -> [[Char]] -> [Char]
    forall a b. (a -> b) -> a -> b
    $ ((([Char], Maybe [Char]), Int) -> [Char])
    -> [(([Char], Maybe [Char]), Int)] -> [[Char]]
    forall a b. (a -> b) -> [a] -> [b]
    map (([Char], Maybe [Char]), Int) -> [Char]
    makeHtml' [(([Char], Maybe [Char]), Int)]
    tags'

    --------------------------------------------------------------------------------
    -- | Render a tag cloud in HTML
    renderTagCloud :: Double
                   -- ^ Smallest font size, in percent
                   -> Double
                   -- ^ Biggest font size, in percent
                   -> Tags
                   -- ^ Input tags
                   -> Compiler String
                   -- ^ Rendered cloud
    renderTagCloud :: Double -> Double -> Tags -> Compiler [Char]
    renderTagCloud = (Double
     -> Double -> [Char] -> [Char] -> Int -> Int -> Int -> [Char])
    -> ([[Char]] -> [Char])
    -> Double
    -> Double
    -> Tags
    -> Compiler [Char]
    renderTagCloudWith Double -> Double -> [Char] -> [Char] -> Int -> Int -> Int -> [Char]
    forall {a} {a} {p} {p} {p} {a}.
    (ToMarkup a, ToValue a, Integral p, Integral p, Integral p,
     RealFrac a) =>
    a -> a -> a -> a -> p -> p -> p -> [Char]
    makeLink ([Char] -> [[Char]] -> [Char]
    forall a. [a] -> [[a]] -> [a]
    intercalate [Char]
    " ")
      where
        makeLink :: a -> a -> a -> a -> p -> p -> p -> [Char]
    makeLink a
    minSize a
    maxSize a
    tag a
    url p
    count p
    min' p
    max' =
            -- Show the relative size of one 'count' in percent
            let diff :: a
    diff     = a
    1 a -> a -> a
    forall a. Num a => a -> a -> a
    + p -> a
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral p
    max' a -> a -> a
    forall a. Num a => a -> a -> a
    - p -> a
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral p
    min'
                relative :: a
    relative = (p -> a
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral p
    count a -> a -> a
    forall a. Num a => a -> a -> a
    - p -> a
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral p
    min') a -> a -> a
    forall a. Fractional a => a -> a -> a
    / a
    diff
                size :: Int
    size     = a -> Int
    forall b. Integral b => a -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    floor (a -> Int) -> a -> Int
    forall a b. (a -> b) -> a -> b
    $ a
    minSize a -> a -> a
    forall a. Num a => a -> a -> a
    + a
    relative a -> a -> a
    forall a. Num a => a -> a -> a
    * (a
    maxSize a -> a -> a
    forall a. Num a => a -> a -> a
    - a
    minSize) :: Int
            in Html -> [Char]
    renderHtml (Html -> [Char]) -> Html -> [Char]
    forall a b. (a -> b) -> a -> b
    $
                Html -> Html
    H.a (Html -> Html) -> Attribute -> Html -> Html
    forall h. Attributable h => h -> Attribute -> h
    ! AttributeValue -> Attribute
    A.style ([Char] -> AttributeValue
    forall a. ToValue a => a -> AttributeValue
    toValue ([Char] -> AttributeValue) -> [Char] -> AttributeValue
    forall a b. (a -> b) -> a -> b
    $ [Char]
    "font-size: " [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ Int -> [Char]
    forall a. Show a => a -> [Char]
    show Int
    size [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    "%")
                    (Html -> Html) -> Attribute -> Html -> Html
    forall h. Attributable h => h -> Attribute -> h
    ! AttributeValue -> Attribute
    A.href (a -> AttributeValue
    forall a. ToValue a => a -> AttributeValue
    toValue a
    url)
                    (Html -> Html) -> Html -> Html
    forall a b. (a -> b) -> a -> b
    $ a -> Html
    forall a. ToMarkup a => a -> Html
    toHtml a
    tag

    --------------------------------------------------------------------------------
    -- | Render a tag cloud in HTML
    renderTagCloudWith :: (Double -> Double ->
                           String -> String -> Int -> Int -> Int -> String)
                       -- ^ Render a single tag link
                       -> ([String] -> String)
                       -- ^ Concatenate links
                       -> Double
                       -- ^ Smallest font size, in percent
                       -> Double
                       -- ^ Biggest font size, in percent
                       -> Tags
                       -- ^ Input tags
                       -> Compiler String
                       -- ^ Rendered cloud
    renderTagCloudWith :: (Double
     -> Double -> [Char] -> [Char] -> Int -> Int -> Int -> [Char])
    -> ([[Char]] -> [Char])
    -> Double
    -> Double
    -> Tags
    -> Compiler [Char]
    renderTagCloudWith Double -> Double -> [Char] -> [Char] -> Int -> Int -> Int -> [Char]
    makeLink [[Char]] -> [Char]
    cat Double
    minSize Double
    maxSize =
      ([Char] -> [Char] -> Int -> Int -> Int -> [Char])
    -> ([[Char]] -> [Char]) -> Tags -> Compiler [Char]
    renderTags (Double -> Double -> [Char] -> [Char] -> Int -> Int -> Int -> [Char]
    makeLink Double
    minSize Double
    maxSize) [[Char]] -> [Char]
    cat

    --------------------------------------------------------------------------------
    -- | Render a tag cloud in HTML as a context
    tagCloudField :: String
                   -- ^ Destination key
                   -> Double
                   -- ^ Smallest font size, in percent
                   -> Double
                   -- ^ Biggest font size, in percent
                   -> Tags
                   -- ^ Input tags
                   -> Context a
                   -- ^ Context
    tagCloudField :: forall a. [Char] -> Double -> Double -> Tags -> Context a
    tagCloudField [Char]
    key Double
    minSize Double
    maxSize Tags
    tags =
      [Char] -> (Item a -> Compiler [Char]) -> Context a
    forall a. [Char] -> (Item a -> Compiler [Char]) -> Context a
    field [Char]
    key ((Item a -> Compiler [Char]) -> Context a)
    -> (Item a -> Compiler [Char]) -> Context a
    forall a b. (a -> b) -> a -> b
    $ \Item a
    _ -> Double -> Double -> Tags -> Compiler [Char]
    renderTagCloud Double
    minSize Double
    maxSize Tags
    tags

    --------------------------------------------------------------------------------
    -- | Render a tag cloud in HTML as a context
    tagCloudFieldWith :: String
                      -- ^ Destination key
                      -> (Double -> Double ->
                          String -> String -> Int -> Int -> Int -> String)
                      -- ^ Render a single tag link
                      -> ([String] -> String)
                      -- ^ Concatenate links
                      -> Double
                      -- ^ Smallest font size, in percent
                      -> Double
                      -- ^ Biggest font size, in percent
                      -> Tags
                      -- ^ Input tags
                      -> Context a
                      -- ^ Context
    tagCloudFieldWith :: forall a.
    [Char]
    -> (Double
        -> Double -> [Char] -> [Char] -> Int -> Int -> Int -> [Char])
    -> ([[Char]] -> [Char])
    -> Double
    -> Double
    -> Tags
    -> Context a
    tagCloudFieldWith [Char]
    key Double -> Double -> [Char] -> [Char] -> Int -> Int -> Int -> [Char]
    makeLink [[Char]] -> [Char]
    cat Double
    minSize Double
    maxSize Tags
    tags =
      [Char] -> (Item a -> Compiler [Char]) -> Context a
    forall a. [Char] -> (Item a -> Compiler [Char]) -> Context a
    field [Char]
    key ((Item a -> Compiler [Char]) -> Context a)
    -> (Item a -> Compiler [Char]) -> Context a
    forall a b. (a -> b) -> a -> b
    $ \Item a
    _ -> (Double
     -> Double -> [Char] -> [Char] -> Int -> Int -> Int -> [Char])
    -> ([[Char]] -> [Char])
    -> Double
    -> Double
    -> Tags
    -> Compiler [Char]
    renderTagCloudWith Double -> Double -> [Char] -> [Char] -> Int -> Int -> Int -> [Char]
    makeLink [[Char]] -> [Char]
    cat Double
    minSize Double
    maxSize Tags
    tags

    --------------------------------------------------------------------------------
    -- | Render a simple tag list in HTML, with the tag count next to the item
    -- TODO: Maybe produce a Context here
    renderTagList :: Tags -> Compiler (String)
    renderTagList :: Tags -> Compiler [Char]
    renderTagList = ([Char] -> [Char] -> Int -> Int -> Int -> [Char])
    -> ([[Char]] -> [Char]) -> Tags -> Compiler [Char]
    renderTags [Char] -> [Char] -> Int -> Int -> Int -> [Char]
    forall {a} {a} {p} {p}.
    (ToValue a, Show a) =>
    [Char] -> a -> a -> p -> p -> [Char]
    makeLink ([Char] -> [[Char]] -> [Char]
    forall a. [a] -> [[a]] -> [a]
    intercalate [Char]
    ", ")
      where
        makeLink :: [Char] -> a -> a -> p -> p -> [Char]
    makeLink [Char]
    tag a
    url a
    count p
    _ p
    _ = Html -> [Char]
    renderHtml (Html -> [Char]) -> Html -> [Char]
    forall a b. (a -> b) -> a -> b
    $
            Html -> Html
    H.a (Html -> Html) -> Attribute -> Html -> Html
    forall h. Attributable h => h -> Attribute -> h
    ! AttributeValue -> Attribute
    A.href (a -> AttributeValue
    forall a. ToValue a => a -> AttributeValue
    toValue a
    url) (Html -> Html) -> Attribute -> Html -> Html
    forall h. Attributable h => h -> Attribute -> h
    ! AttributeValue -> Attribute
    A.rel AttributeValue
    "tag" (Html -> Html) -> Html -> Html
    forall a b. (a -> b) -> a -> b
    $ [Char] -> Html
    forall a. ToMarkup a => a -> Html
    toHtml ([Char]
    tag [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    " (" [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ a -> [Char]
    forall a. Show a => a -> [Char]
    show a
    count [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    ")")

    --------------------------------------------------------------------------------
    -- | Render tags with links with custom functions to get tags and to
    -- render links
    tagsFieldWith :: (Identifier -> Compiler [String])
                  -- ^ Get the tags
                  -> (String -> (Maybe FilePath) -> Maybe H.Html)
                  -- ^ Render link for one tag
                  -> ([H.Html] -> H.Html)
                  -- ^ Concatenate tag links
                  -> String
                  -- ^ Destination field
                  -> Tags
                  -- ^ Tags structure
                  -> Context a
                  -- ^ Resulting context
    tagsFieldWith :: forall a.
    (Identifier -> Compiler [[Char]])
    -> ([Char] -> Maybe [Char] -> Maybe Html)
    -> ([Html] -> Html)
    -> [Char]
    -> Tags
    -> Context a
    tagsFieldWith Identifier -> Compiler [[Char]]
    getTags' [Char] -> Maybe [Char] -> Maybe Html
    renderLink [Html] -> Html
    cat [Char]
    key Tags
    tags = [Char] -> (Item a -> Compiler [Char]) -> Context a
    forall a. [Char] -> (Item a -> Compiler [Char]) -> Context a
    field [Char]
    key ((Item a -> Compiler [Char]) -> Context a)
    -> (Item a -> Compiler [Char]) -> Context a
    forall a b. (a -> b) -> a -> b
    $ \Item a
    item -> do
        [[Char]]
    tags' <- Identifier -> Compiler [[Char]]
    getTags' (Identifier -> Compiler [[Char]])
    -> Identifier -> Compiler [[Char]]
    forall a b. (a -> b) -> a -> b
    $ Item a -> Identifier
    forall a. Item a -> Identifier
    itemIdentifier Item a
    item
        [Maybe Html]
    links <- [[Char]]
    -> ([Char] -> Compiler (Maybe Html)) -> Compiler [Maybe Html]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    t a -> (a -> m b) -> m (t b)
    forM [[Char]]
    tags' (([Char] -> Compiler (Maybe Html)) -> Compiler [Maybe Html])
    -> ([Char] -> Compiler (Maybe Html)) -> Compiler [Maybe Html]
    forall a b. (a -> b) -> a -> b
    $ \[Char]
    tag -> do
            Maybe [Char]
    route' <- Identifier -> Compiler (Maybe [Char])
    getRoute (Identifier -> Compiler (Maybe [Char]))
    -> Identifier -> Compiler (Maybe [Char])
    forall a b. (a -> b) -> a -> b
    $ Tags -> [Char] -> Identifier
    tagsMakeId Tags
    tags [Char]
    tag
            Maybe Html -> Compiler (Maybe Html)
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe Html -> Compiler (Maybe Html))
    -> Maybe Html -> Compiler (Maybe Html)
    forall a b. (a -> b) -> a -> b
    $ [Char] -> Maybe [Char] -> Maybe Html
    renderLink [Char]
    tag Maybe [Char]
    route'

        [Char] -> Compiler [Char]
    forall a. a -> Compiler a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Char] -> Compiler [Char]) -> [Char] -> Compiler [Char]
    forall a b. (a -> b) -> a -> b
    $ Html -> [Char]
    renderHtml (Html -> [Char]) -> Html -> [Char]
    forall a b. (a -> b) -> a -> b
    $ [Html] -> Html
    cat ([Html] -> Html) -> [Html] -> Html
    forall a b. (a -> b) -> a -> b
    $ [Maybe Html] -> [Html]
    forall a. [Maybe a] -> [a]
    catMaybes ([Maybe Html] -> [Html]) -> [Maybe Html] -> [Html]
    forall a b. (a -> b) -> a -> b
    $ [Maybe Html]
    links

    --------------------------------------------------------------------------------
    -- | Render tags with links
    tagsField :: String     -- ^ Destination key
              -> Tags       -- ^ Tags
              -> Context a  -- ^ Context
    tagsField :: forall a. [Char] -> Tags -> Context a
    tagsField =
      (Identifier -> Compiler [[Char]])
    -> ([Char] -> Maybe [Char] -> Maybe Html)
    -> ([Html] -> Html)
    -> [Char]
    -> Tags
    -> Context a
    forall a.
    (Identifier -> Compiler [[Char]])
    -> ([Char] -> Maybe [Char] -> Maybe Html)
    -> ([Html] -> Html)
    -> [Char]
    -> Tags
    -> Context a
    tagsFieldWith Identifier -> Compiler [[Char]]
    forall (m :: * -> *). MonadMetadata m => Identifier -> m [[Char]]
    getTags [Char] -> Maybe [Char] -> Maybe Html
    simpleRenderLink ([Html] -> Html
    forall a. Monoid a => [a] -> a
    mconcat ([Html] -> Html) -> ([Html] -> [Html]) -> [Html] -> Html
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Html -> [Html] -> [Html]
    forall a. a -> [a] -> [a]
    intersperse Html
    ", ")

    --------------------------------------------------------------------------------
    -- | Render the category in a link
    categoryField :: String     -- ^ Destination key
                  -> Tags       -- ^ Tags
                  -> Context a  -- ^ Context
    categoryField :: forall a. [Char] -> Tags -> Context a
    categoryField =
      (Identifier -> Compiler [[Char]])
    -> ([Char] -> Maybe [Char] -> Maybe Html)
    -> ([Html] -> Html)
    -> [Char]
    -> Tags
    -> Context a
    forall a.
    (Identifier -> Compiler [[Char]])
    -> ([Char] -> Maybe [Char] -> Maybe Html)
    -> ([Html] -> Html)
    -> [Char]
    -> Tags
    -> Context a
    tagsFieldWith Identifier -> Compiler [[Char]]
    forall (m :: * -> *). MonadMetadata m => Identifier -> m [[Char]]
    getCategory [Char] -> Maybe [Char] -> Maybe Html
    simpleRenderLink ([Html] -> Html
    forall a. Monoid a => [a] -> a
    mconcat ([Html] -> Html) -> ([Html] -> [Html]) -> [Html] -> Html
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Html -> [Html] -> [Html]
    forall a. a -> [a] -> [a]
    intersperse Html
    ", ")

    --------------------------------------------------------------------------------
    -- | Render one tag link
    simpleRenderLink :: String -> (Maybe FilePath) -> Maybe H.Html
    simpleRenderLink :: [Char] -> Maybe [Char] -> Maybe Html
    simpleRenderLink [Char]
    _   Maybe [Char]
    Nothing         = Maybe Html
    forall a. Maybe a
    Nothing
    simpleRenderLink [Char]
    tag (Just [Char]
    filePath) = Html -> Maybe Html
    forall a. a -> Maybe a
    Just (Html -> Maybe Html) -> Html -> Maybe Html
    forall a b. (a -> b) -> a -> b
    $
        Html -> Html
    H.a (Html -> Html) -> Attribute -> Html -> Html
    forall h. Attributable h => h -> Attribute -> h
    ! AttributeValue -> Attribute
    A.title ([Char] -> AttributeValue
    H.stringValue ([Char]
    "All pages tagged '"[Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++[Char]
    tag[Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++[Char]
    "'."))
            (Html -> Html) -> Attribute -> Html -> Html
    forall h. Attributable h => h -> Attribute -> h
    ! AttributeValue -> Attribute
    A.href ([Char] -> AttributeValue
    forall a. ToValue a => a -> AttributeValue
    toValue ([Char] -> AttributeValue) -> [Char] -> AttributeValue
    forall a b. (a -> b) -> a -> b
    $ [Char] -> [Char]
    toUrl [Char]
    filePath)
            (Html -> Html) -> Attribute -> Html -> Html
    forall h. Attributable h => h -> Attribute -> h
    ! (AttributeValue -> Attribute
    A.rel AttributeValue
    "tag")
            (Html -> Html) -> Html -> Html
    forall a b. (a -> b) -> a -> b
    $ [Char] -> Html
    forall a. ToMarkup a => a -> Html
    toHtml [Char]
    tag

    --------------------------------------------------------------------------------
    -- | Sort tags using supplied function. First element of the tuple passed to
    -- the comparing function is the actual tag name.
    sortTagsBy :: ((String, [Identifier]) -> (String, [Identifier]) -> Ordering)
               -> Tags -> Tags
    sortTagsBy :: (([Char], [Identifier]) -> ([Char], [Identifier]) -> Ordering)
    -> Tags -> Tags
    sortTagsBy ([Char], [Identifier]) -> ([Char], [Identifier]) -> Ordering
    f Tags
    t = Tags
    t {tagsMap :: [([Char], [Identifier])]
    tagsMap = (([Char], [Identifier]) -> ([Char], [Identifier]) -> Ordering)
    -> [([Char], [Identifier])] -> [([Char], [Identifier])]
    forall a. (a -> a -> Ordering) -> [a] -> [a]
    sortBy ([Char], [Identifier]) -> ([Char], [Identifier]) -> Ordering
    f (Tags -> [([Char], [Identifier])]
    tagsMap Tags
    t)}

    --------------------------------------------------------------------------------
    -- | Sample sorting function that compares tags case insensitively.
    caseInsensitiveTags :: (String, [Identifier]) -> (String, [Identifier])
                        -> Ordering
    caseInsensitiveTags :: ([Char], [Identifier]) -> ([Char], [Identifier]) -> Ordering
    caseInsensitiveTags = (([Char], [Identifier]) -> [Char])
    -> ([Char], [Identifier]) -> ([Char], [Identifier]) -> Ordering
    forall a b. Ord a => (b -> a) -> b -> b -> Ordering
    comparing ((([Char], [Identifier]) -> [Char])
     -> ([Char], [Identifier]) -> ([Char], [Identifier]) -> Ordering)
    -> (([Char], [Identifier]) -> [Char])
    -> ([Char], [Identifier])
    -> ([Char], [Identifier])
    -> Ordering
    forall a b. (a -> b) -> a -> b
    $ (Char -> Char) -> [Char] -> [Char]
    forall a b. (a -> b) -> [a] -> [b]
    map Char -> Char
    toLower ([Char] -> [Char])
    -> (([Char], [Identifier]) -> [Char])
    -> ([Char], [Identifier])
    -> [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ([Char], [Identifier]) -> [Char]
    forall a b. (a, b) -> a
    fst