content: -- Copyright (c) 2016-present, Facebook, Inc.
  -- All rights reserved.
  --
  -- This source code is licensed under the BSD-style license found in the
  -- LICENSE file in the root directory of this source tree.
  
  
  {-# LANGUAGE GADTs #-}
  {-# LANGUAGE NoRebindableSyntax #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE LambdaCase #-}
  
  module Duckling.Time.CA.Rules
    ( rules
    ) where
  
  import Prelude
  import qualified Data.Text as Text
  
  import Duckling.Dimensions.Types
  import Duckling.Duration.Helpers (isGrain)
  import Duckling.Numeral.Helpers (parseInt)
  import Duckling.Ordinal.Types (OrdinalData(..))
  import Duckling.Regex.Types
  import Duckling.Time.Helpers
  import Duckling.Time.Types (TimeData(..))
  import Duckling.Types
  import qualified Duckling.Ordinal.Types as TOrdinal
  import qualified Duckling.Time.Types as TTime
  import qualified Duckling.TimeGrain.Types as TG
  
  ruleTheDayAfterTomorrow :: Rule
  ruleTheDayAfterTomorrow = Rule
    { name = "the day after tomorrow"
    , pattern =
      [ regex "dem(a|à) passat|l'endem(a|à)|passat dem(a|à)"
      ]
    , prod = \_ -> tt $ cycleNth TG.Day 2
    }
  
  ruleHaceDuration :: Rule
  ruleHaceDuration = Rule
    { name = "fa <duration>"
    , pattern =
      [ regex "fa"
      , dimension Duration
      ]
    , prod = \case
        (_:Token Duration dd:_) ->
          tt $ durationAgo dd
        _ -> Nothing
    }
  
  ruleCeTime :: Rule
  ruleCeTime = Rule
    { name = "ce <time>"
    , pattern =
      [ regex "aquest"
      , dimension Time
      ]
    , prod = \case
        (_:Token Time td:_) ->
          tt $ predNth 0 False td
        _ -> Nothing
    }
  
  ruleDaysOfWeek :: [Rule]
  ruleDaysOfWeek = mkRuleDaysOfWeek
    [ ( "Dilluns"   , "dilluns|dl\\.?" )
    , ( "Dimarts"   , "dimarts|dm\\.?" )
    , ( "Dimecres"  , "dimecres|dc\\.?" )
    , ( "Dijous"    , "dijous|dj\\.?" )
    , ( "Divendres" , "divendres|dv\\.?" )
    , ( "Dissabte"  , "dissabte|ds\\.?" )
    , ( "Diumenge"  , "diumenge|dg\\.?" )
    ]
  
  ruleMonths :: [Rule]
  ruleMonths = mkRuleMonths
    [ ( "Gener"    , "gener|gen\\.?")
    , ( "Febrer"   , "febrer|feb\\.?")
    , ( "Març"     , "març|mar\\.?")
    , ( "Abril"    , "abril|abr\\.?")
    , ( "Maig"     , "maig?\\.?")
    , ( "Juny"     , "juny?\\.?")
    , ( "Juliol"   , "juliol|jul\\.?")
    , ( "Agost"    , "agost|ago\\.?")
    , ( "Setembre" , "setembre|set\\.?")
    , ( "Octubre"  , "octubre|oct\\.?")
    , ( "Novembre" , "novembre|nov\\.?")
    , ( "Desembre" , "desembre|des\\.?")
    ]
  
  ruleThisDayofweek :: Rule
  ruleThisDayofweek = Rule
    { name = "this <day-of-week>"
    , pattern =
      [ regex "aquest"
      , Predicate isADayOfWeek
      ]
    , prod = \case
        (_:Token Time td:_) ->
          tt $ predNth 0 True td
        _ -> Nothing
    }
  
  ruleDatetimeDatetimeInterval :: Rule
  ruleDatetimeDatetimeInterval = Rule
    { name = "<datetime> - <datetime> (interval)"
    , pattern =
      [ Predicate isNotLatent
      , regex "\\s?-\\s?|\\sal?\\s"
      , Predicate isNotLatent
      ]
    , prod = \case
        (Token Time td1:_:Token Time td2:_) ->
          Token Time <$> interval TTime.Open td1 td2
        _ -> Nothing
    }
  
  ruleEvening :: Rule
  ruleEvening = Rule
    { name = "evening"
    , pattern =
      [ regex "vespre"
      ]
    , prod = \_ ->
        let from = hour False 19
            to = hour False 22
        in Token Time . mkLatent . partOfDay <$>
             interval TTime.Open from to
    }
  
  -- Afegit Xavier Plaza
  ruleMatinada:: Rule
  ruleMatinada = Rule
    { name = "matinada"
    , pattern =
      [ regex "matinada"
      ]
    , prod = \_ ->
        let from = hour False 1
            to = hour False 6
        in Token Time . mkLatent . partOfDay <$>
             interval TTime.Open from to
    }
  
  ruleNit:: Rule
  ruleNit = Rule
    { name = "nit"
    , pattern =
      [ regex "nit"
      ]
    , prod = \_ ->
        let from = hour False 22
            to = hour False 1
        in Token Time . mkLatent . partOfDay <$>
             interval TTime.Open from to
    }
  
  ruleMigdia:: Rule
  ruleMigdia = Rule
    { name = "migdia"
    , pattern =
      [ regex "migdia|mig dia"
      ]
    , prod = \_ ->
        let from = hour False 11
            to = hour False 14
        in Token Time . mkLatent . partOfDay <$>
             interval TTime.Open from to
    }
  
  ruleDayOfMonthSt :: Rule
  ruleDayOfMonthSt = Rule
    { name = "day of month (1st)"
    , pattern =
      [ regex "primer|u|1er( de)?"
      ]
    , prod = \_ -> tt $ dayOfMonth 1
    }
  
  ruleEnDuration :: Rule
  ruleEnDuration = Rule
    { name = "en <duration>"
    , pattern =
      [ regex "\\sen\\s"
      , dimension Duration
      ]
    , prod = \case
        (_:Token Duration dd:_) ->
          tt $ inDuration dd
        _ -> Nothing
    }
  
  ruleToday :: Rule
  ruleToday = Rule
    { name = "today"
    , pattern =
      [ regex "avui"
      ]
    , prod = \_ -> tt today
    }
  
  ruleUltimoDayofweekDeTime :: Rule
  ruleUltimoDayofweekDeTime = Rule
    { name = "ultimo <day-of-week> de <time>"
    , pattern =
      [ regex "darrer"
      , Predicate isADayOfWeek
      , regex "de|d'"
      , dimension Time
      ]
    , prod = \case
        (_:Token Time td1:_:Token Time td2:_) ->
          tt $ predLastOf td1 td2
        _ -> Nothing
    }
  
  ruleEntreDatetimeEtDatetimeInterval :: Rule
  ruleEntreDatetimeEtDatetimeInterval = Rule
    { name = "entre <datetime> et <datetime> (interval)"
    , pattern =
      [ regex "(entre|entre les|entre la)"
      , dimension Time
      , regex "(i|i les|i la)"
      , dimension Time
      ]
    , prod = \case
        (_:Token Time td1:_:Token Time td2:_) ->
          Token Time <$> interval TTime.Open td1 td2
        _ -> Nothing
    }
  
  ruleHhhmmTimeOfDay :: Rule
  ruleHhhmmTimeOfDay = Rule
    { name = "hh(:|.|h)mm (time-of-day)"
    , pattern =
      [ regex "((?:[01]?\\d)|(?:2[0-3]))[:h\\.]([0-5]\\d)"
      ]
    , prod = \case
        (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do
          h <- parseInt m1
          m <- parseInt m2
          tt $ hourMinute True h m
        _ -> Nothing
    }
  
  ruleElDayOfMonthDeNamedMonth :: Rule
  ruleElDayOfMonthDeNamedMonth = Rule
    { name = "el <day-of-month> de <named-month>"
    , pattern =
      [ regex "el|l'"
      , Predicate isDOMInteger
      , regex "de|d'"
      , Predicate isAMonth
      ]
    , prod = \case
        (_:t:_:Token Time td:_) -> Token Time <$> intersectDOM td t
        _ -> Nothing
    }
  
  ruleNPasadosCycle :: Rule
  ruleNPasadosCycle = Rule
    { name = "n pasados <cycle>"
    , pattern =
      [ Predicate $ isIntegerBetween 2 9999
      , regex "passa(ts?|da|des)|darrer(s|a|es)?"
      , dimension TimeGrain
      ]
    , prod = \case
        (t:_:Token TimeGrain grain:_) -> do
          v <- getIntValue t
          tt $ cycleN True grain (- v)
        _ -> Nothing
    }
  
  ruleElProximoCycle :: Rule
  ruleElProximoCycle = Rule
    { name = "el proximo <cycle> "
    , pattern =
      [ regex "((el|els|la|les) )?"
      , regex "proper(a|s|es)?"
      , dimension TimeGrain
      ]
    , prod = \case
        (_:_:Token TimeGrain grain:_) ->
          tt $ cycleNth grain 1
        _ -> Nothing
    }
  
  rulePasadosNCycle :: Rule
  rulePasadosNCycle = Rule
    { name = "pasados n <cycle>"
    , pattern =
      [ regex "passa(ts?|da|des)|darrer(s|a|es)?"
      , Predicate $ isIntegerBetween 2 9999
      , dimension TimeGrain
      ]
    , prod = \case
        (_:t:Token TimeGrain grain:_) -> do
          v <- getIntValue t
          tt $ cycleN True grain (- v)
        _ -> Nothing
    }
  
  ruleElDayOfMonthNonOrdinal :: Rule
  ruleElDayOfMonthNonOrdinal = Rule
    { name = "el <day-of-month> (non ordinal)"
    , pattern =
      [ regex "el|l'"
      , Predicate $ isIntegerBetween 1 31
      ]
    , prod = \case
        (_:t:_) -> do
          v <- getIntValue t
          tt $ dayOfMonth v
        _ -> Nothing
    }
  
  ruleNoon :: Rule
  ruleNoon = Rule
    { name = "noon"
    , pattern =
      [ regex "migdia|mig dia"
      ]
    , prod = \_ -> tt $ hour False 12
    }
  
  ruleProximasNCycle :: Rule
  ruleProximasNCycle = Rule
    { name = "proximas n <cycle>"
    , pattern =
      [ regex "proper(a|s|es)?"
      , Predicate $ isIntegerBetween 2 9999
      , dimension TimeGrain
      ]
    , prod = \case
        (_:t:Token TimeGrain grain:_) -> do
          v <- getIntValue t
          tt $ cycleN True grain v
        _ -> Nothing
    }
  
  ruleNochevieja :: Rule
  ruleNochevieja = Rule
    { name = "Nochevieja"
    , pattern =
      [ regex "(nit de cap d'any|darrer dia de l'any)"
      ]
    , prod = \_ -> tt $ monthDay 12 31
    }
  
  ruleTheDayBeforeYesterday :: Rule
  ruleTheDayBeforeYesterday = Rule
    { name = "the day before yesterday"
    , pattern =
      [ regex "abans d'ahir"
      ]
    , prod = \_ -> tt $ cycleNth TG.Day (-2)
    }
  
  -- TODO: add within/after
  ruleDurationIn :: Rule
  ruleDurationIn = Rule
    { name = "in <duration>"
    , pattern =
      [ regex "en"
      , dimension Duration
      ]
    , prod = \case
        (_:Token Duration dd:_) -> tt $ inDuration dd
        _ -> Nothing
    }
  
  ruleDurationAgo :: Rule
  ruleDurationAgo = Rule
    { name = "<duration> ago"
    , pattern =
      [ regex "fa"
      , dimension Duration
      ]
    , prod = \case
        (_:Token Duration dd:_) -> tt $ durationAgo dd
        _ -> Nothing
    }
  
  ruleHourOfDayIntegerAsRelativeMinutes :: Rule
  ruleHourOfDayIntegerAsRelativeMinutes = Rule
    { name = "<hour-of-day> <integer> (as relative minutes)"
    , pattern =
      [ Predicate $ and . sequence [isAnHourOfDay]
      , Predicate $ isIntegerBetween 1 59
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
         minutes:
         _) -> do
          n <- getIntValue minutes
          tt $ hourMinute is12H hours n
        _ -> Nothing
    }
  
  -- Hores format campanar --
  ruleHourOfDayMigQuart :: Rule
  ruleHourOfDayMigQuart = Rule
    { name = "mig quart de <hour-of-day>"
    , pattern =
      [ regex "mig quart (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 53 td
        _ -> Nothing
    }
  
  ruleHourOfDayUnQuart :: Rule
  ruleHourOfDayUnQuart = Rule
    { name = "(un|1)(\\squart|\\/4) de <hour-of-day>"
    , pattern =
      [ regex "un quart (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 45 td
        _ -> Nothing
    }
  
  ruleHourOfDayUnQuartiCinc :: Rule
  ruleHourOfDayUnQuartiCinc = Rule
    { name = "un quart i cinc de <hour-of-day>"
    , pattern =
      [ regex "((un quart|1\\/4) i cinc|(dos|2)(\\squarts|\\/4) menys deu) (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 40 td
        _ -> Nothing
    }
  
  ruleHourOfDayUnQuartiMig :: Rule
  ruleHourOfDayUnQuartiMig = Rule
    { name = "un quart i mig de <hour-of-day>"
    , pattern =
      [ regex "(un|1)(\\squart|\\/4) i mig (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 38 td
        _ -> Nothing
    }
  
  ruleHourOfDayUnQuartiDeu :: Rule
  ruleHourOfDayUnQuartiDeu = Rule
    { name = "un quart i deu de <hour-of-day>"
    , pattern =
      [ regex "((un|1)(\\squart|\\/4) i deu|(dos|2)(\\squarts|\\/4) menys cinc) (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 35 td
        _ -> Nothing
    }
  
  ruleHourOfDayDosQuarts :: Rule
  ruleHourOfDayDosQuarts = Rule
    { name = "dos quarts de <hour-of-day>"
    , pattern =
      [ regex "((dos|2)(\\squarts|\\/4)|quarts) (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 30 td
        _ -> Nothing
    }
  
  ruleHourOfDayDosQuartsiCinc :: Rule
  ruleHourOfDayDosQuartsiCinc = Rule
    { name = "dos quarts i cinc de <hour-of-day>"
    , pattern =
      [ regex "((dos|2)(\\squarts|\\/4) i cinc|(tres|3)(\\squarts|\\/4) menys deu) (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 25 td
        _ -> Nothing
    }
  
  ruleHourOfDayDosQuartsiMig :: Rule
  ruleHourOfDayDosQuartsiMig = Rule
    { name = "dos quarts i mig de <hour-of-day>"
    , pattern =
      [ regex "(dos|2)(\\squarts|\\/4) i mig (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 23 td
        _ -> Nothing
    }
  
  ruleHourOfDayDosQuartsiDeu :: Rule
  ruleHourOfDayDosQuartsiDeu = Rule
    { name = "Dos quarts i deu de <hour-of-day>"
    , pattern =
      [ regex "((dos|2)(\\squarts|\\/4) i deu|(tres|3)(\\squarts|\\/4) menys cinc) (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 20 td
        _ -> Nothing
    }
  
  ruleHourOfDayTresQuarts :: Rule
  ruleHourOfDayTresQuarts = Rule
    { name = "tres quarts de <hour-of-day>"
    , pattern =
      [ regex "(tres|3)(\\squarts|\\/4) (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 15 td
        _ -> Nothing
    }
  
  ruleHourOfDayTresQuartsiCinc :: Rule
  ruleHourOfDayTresQuartsiCinc = Rule
    { name = "Tres quarts i cinc de <hour-of-day>"
    , pattern =
      [ regex "(tres|3)(\\squarts|\\/4) i cinc (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 10 td
        _ -> Nothing
    }
  
  ruleHourOfDayTresQuartsiMig :: Rule
  ruleHourOfDayTresQuartsiMig = Rule
    { name = "Tres quarts i mig de <hour-of-day>"
    , pattern =
      [ regex "(tres|3)(\\squarts|\\/4) i mig (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 8 td
        _ -> Nothing
    }
  
  ruleHourOfDayTresQuartsiDeu :: Rule
  ruleHourOfDayTresQuartsiDeu = Rule
    { name = "Tres quarts i deu de <hour-of-day>"
    , pattern =
      [ regex "(tres|3)(\\squarts|\\/4) i deu (de |d')"
      , Predicate isAnHourOfDay
      ]
    , prod = \case
        (Token Time td:_) -> Token Time <$> minutesBefore 20 td
        _ -> Nothing
    }
  
  -- Final Hores format campanar --
  
  ruleHourOfDayIntegerAsRelativeMinutes2 :: Rule
  ruleHourOfDayIntegerAsRelativeMinutes2 = Rule
    { name = "<hour-of-day> <integer> (as relative minutes) minutes"
    , pattern =
      [ Predicate isAnHourOfDay
      , Predicate $ isIntegerBetween 1 59
      , regex "min\\.?(ut)?s?"
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
         t:
         _) -> do
          n <- getIntValue t
          tt $ hourMinute is12H hours n
        _ -> Nothing
    }
  
  ruleHourOfDayQuarter :: Rule
  ruleHourOfDayQuarter = Rule
    { name = "<hour-of-day> quarter (as relative minutes)"
    , pattern =
      [ Predicate isAnHourOfDay
      , regex "quart"
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) ->
          tt $ hourMinute is12H hours 15
        _ -> Nothing
    }
  
  ruleHourOfDayHalf :: Rule
  ruleHourOfDayHalf = Rule
    { name = "<hour-of-day> half (as relative minutes)"
    , pattern =
      [ Predicate isAnHourOfDay
      , regex "mitja|(2|dos)(\\squarts|\\/4)"
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) ->
          tt $ hourMinute is12H hours 30
        _ -> Nothing
    }
  
  ruleHourOfDayThreeQuarter :: Rule
  ruleHourOfDayThreeQuarter = Rule
    { name = "<hour-of-day> three quarters (as relative minutes)"
    , pattern =
      [ Predicate isAnHourOfDay
      , regex "(3|tres)(\\squarts|\\/4)"
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) ->
          tt $ hourMinute is12H hours 45
        _ -> Nothing
    }
  
  ruleHourOfDayAndRelativeMinutes :: Rule
  ruleHourOfDayAndRelativeMinutes = Rule
    { name = "<hour-of-day> and <relative minutes>"
    , pattern =
      [ Predicate isAnHourOfDay
      , regex "i"
      , Predicate $ isIntegerBetween 1 59
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
         _:
         t:
         _) -> do
          n <- getIntValue t
          tt $ hourMinute is12H hours n
        _ -> Nothing
    }
  
  ruleHourOfDayAndRelativeMinutes2 :: Rule
  ruleHourOfDayAndRelativeMinutes2 = Rule
    { name = "<hour-of-day> and <relative minutes> minutes"
    , pattern =
      [ Predicate isAnHourOfDay
      , regex "i"
      , Predicate $ isIntegerBetween 1 59
      , regex "min\\.?(ut)?s?"
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
         _:
         t:
         _) -> do
          n <- getIntValue t
          tt $ hourMinute is12H hours n
        _ -> Nothing
    }
  
  ruleHourOfDayAndQuarter :: Rule
  ruleHourOfDayAndQuarter = Rule
    { name = "<hour-of-day> and quarter"
    , pattern =
      [ Predicate isAnHourOfDay
      , regex "i quart"
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) ->
          tt $ hourMinute is12H hours 15
        _ -> Nothing
    }
  
  ruleHourOfDayAndHalf :: Rule
  ruleHourOfDayAndHalf = Rule
    { name = "<hour-of-day> and half"
    , pattern =
      [ Predicate isAnHourOfDay
      , regex "i (mitja|(2|dos)(\\squarts|\\/4))"
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) ->
          tt $ hourMinute is12H hours 30
        _ -> Nothing
    }
  
  ruleHourOfDayAndThreeQuarter :: Rule
  ruleHourOfDayAndThreeQuarter = Rule
    { name = "<hour-of-day> and 3 quarters"
    , pattern =
      [ Predicate isAnHourOfDay
      , regex "i (tres|3)(\\squarts|\\/4)"
      ]
    , prod = \case
        (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) ->
          tt $ hourMinute is12H hours 45
        _ -> Nothing
    }
  
  ruleDelYear :: Rule
  ruleDelYear = Rule
    { name = "del <year>"
    , pattern =
      [ regex "de(l| l'any)? "
      , Predicate $ isIntegerBetween 1000 2100
      ]
    , prod = \case
        (_:t:_) -> do
          v <- getIntValue t
          tt $ year v
        _ -> Nothing
    }
  
  -- Revisar per que diria que no va bé
  ruleDdmm :: Rule
  ruleDdmm = Rule
    { name = "dd[/-]mm"
    , pattern =
      [ regex "(3[01]|[12]\\d|0?[1-9])[/-](0?[1-9]|1[0-2])( |$)"
      ]
    , prod = \case
        (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do
          d <- parseInt m1
          m <- parseInt m2
          tt $ monthDay m d
        _ -> Nothing
    }
  
  ruleDdmmyyyy :: Rule
  ruleDdmmyyyy = Rule
    { name = "dd[/-.]mm[/-.]yyyy"
    , pattern =
      [ regex "(3[01]|[12]\\d|0?[1-9])[\\./-](0?[1-9]|1[0-2])[\\./-](\\d{2,4})"
      ]
    , prod = \case
        (Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
          d <- parseInt m1
          m <- parseInt m2
          y <- parseInt m3
          tt $ yearMonthDay y m d
        _ -> Nothing
    }
  
  ruleAfternoon :: Rule
  ruleAfternoon = Rule
    { name = "afternoon"
    , pattern =
      [ regex "tarda"
      ]
    , prod = \_ ->
        let from = hour False 14
            to = hour False 19
        in Token Time . mkLatent . partOfDay <$>
             interval TTime.Open from to
    }
  
  ruleMidnight :: Rule
  ruleMidnight = Rule
    { name = "midnight"
    , pattern =
      [ regex "mitjanit|mitja nit"
      ]
    , prod = \_ -> tt $ hour False 0
    }
  
  rulePODIn :: Rule
  rulePODIn = Rule
    { name = "in the <part-of-day>"
    , pattern =
      [ regex "(a la|al|per la|pel|del)"
      , Predicate isAPartOfDay
      ]
    , prod = \case
        (_:Token Time td:_) -> tt $ notLatent td
        _ -> Nothing
    }
  
  rulePODThis :: Rule
  rulePODThis = Rule
    { name = "this <part-of-day>"
    , pattern =
      [ regex "aquesta?"
      , Predicate isAPartOfDay
      ]
    , prod = \case
        (_:Token Time td:_) -> Token Time . partOfDay . notLatent <$> intersect today td
        _ -> Nothing
    }
  
  ruleTODPOD :: Rule
  ruleTODPOD = Rule
    { name = "<time-of-day> <part-of-day>"
    , pattern =
      [ Predicate isATimeOfDay
      , Predicate isAPartOfDay
      ]
    , prod = \tokens -> case tokens of
        (Token Time td:Token Time pod:_) -> Token Time . notLatent <$> intersect td pod
        _ -> Nothing
    }
  
  ruleAnoNuevo :: Rule
  ruleAnoNuevo = Rule
    { name = "ano nuevo"
    , pattern =
      [ regex "cap d'any"
      ]
    , prod = \_ -> tt $ monthDay 1 1
    }
  
  ruleDdddMonthinterval :: Rule
  ruleDdddMonthinterval = Rule
    { name = "dd-dd <month>(interval)"
    , pattern =
      [ regex "(3[01]|[12]\\d|0?[1-9])" -- Revisar per que diria que no va bé
      , regex "\\-|al?"
      , regex "(3[01]|[12]\\d|0?[1-9])"
      , regex "de|d'"
      , Predicate isAMonth
      ]
    , prod = \case
        (Token RegexMatch (GroupMatch (m1:_)):
         _:
         Token RegexMatch (GroupMatch (m2:_)):
         _:
         Token Time td:
         _) -> do
          d1 <- parseInt m1
          d2 <- parseInt m2
          from <- intersect (dayOfMonth d1) td
          to <- intersect (dayOfMonth d2) td
          Token Time <$> interval TTime.Closed from to
        _ -> Nothing
    }
  
  ruleTimeOfDayLatent :: Rule
  ruleTimeOfDayLatent = Rule
    { name = "time-of-day (latent)"
    , pattern =
      [ Predicate $ isIntegerBetween 0 23
      ]
    , prod = \case
        (t:_) -> do
          v <- getIntValue t
          tt $ mkLatent $ hour (v < 13) v
        _ -> Nothing
    }
  
  ruleNamedMonthNamedDayPast :: Rule
  ruleNamedMonthNamedDayPast = Rule
    { name = "<named-month|named-day> past"
    , pattern =
      [ dimension Time
      , regex "passat"
      ]
    , prod = \case
        (Token Time td:_) ->
          tt $ predNth (-1) False td
        _ -> Nothing
    }
  
  ruleNamedMonthNamedDayPast2 :: Rule
  ruleNamedMonthNamedDayPast2 = Rule
    { name = "<named-month|named-day> past"
    , pattern =
      [ regex "passat|darrer|l'ultim"
      , dimension Time
      ]
    , prod = \case
        (Token Time td:_) ->
          tt $ predNth (-1) False td
        _ -> Nothing
    }
  
  ruleSeasons :: [Rule]
  ruleSeasons = mkRuleSeasons
    [ ( "estiu"   , "estiu"   , monthDay  6 21, monthDay  9 23 )
    , ( "tardor"    , "tardor", monthDay  9 23, monthDay 12 21 )
    , ( "hivern" , "hivern" , monthDay 12 21, monthDay  3 20 )
    , ( "primavera", "primavera", monthDay  3 20, monthDay  6 21 )
    ]
  
  ruleRightNow :: Rule
  ruleRightNow = Rule
    { name = "right now"
    , pattern =
      [ regex "ara( mateix)?|ja|en aquests? moments?|tant aviat com puguis?"
      ]
    , prod = \_ -> tt now
    }
  
  ruleNCycleVinent :: Rule
  ruleNCycleVinent = Rule
    { name = "n <cycle> (proximo|que viene)"
    , pattern =
      [ Predicate $ isIntegerBetween 2 9999
      , dimension TimeGrain
      , regex "(vinents?)"
      ]
    , prod = \case
        (t:Token TimeGrain grain:_) -> do
          v <- getIntValue t
          tt $ cycleN True grain v
        _ -> Nothing
    }
  
  ruleNamedMonthNamedDayNext :: Rule
  ruleNamedMonthNamedDayNext = Rule
    { name = "<named-month|named-day> next"
    , pattern =
      [ dimension Time
      , regex "vinents?"
      ]
    , prod = \case
        (Token Time td:_) ->
          tt $ predNth 1 False td
        _ -> Nothing
    }
  
  -- afegir la mateixa regla però ficant devant proper
  
  ruleIntersect :: Rule
  ruleIntersect = Rule
    { name = "intersect"
    , pattern =
      [ Predicate isNotLatent
      , Predicate isNotLatent
      ]
    , prod = \case
        (Token Time td1:Token Time td2:_) ->
          Token Time <$> intersect td1 td2
        _ -> Nothing
    }
  
  ruleDeDatetimeDatetimeInterval :: Rule
  ruleDeDatetimeDatetimeInterval = Rule
    { name = "de <datetime> - <datetime> (interval)"
    , pattern =
      [ regex "(des )?del?"
      , dimension Time
      , regex "\\-|(fins )?al?"
      , dimension Time
      ]
    , prod = \case
        (_:Token Time td1:_:Token Time td2:_) ->
          Token Time <$> interval TTime.Open td1 td2
        _ -> Nothing
    }
  
  ruleNthTimeDeTime2 :: Rule
  ruleNthTimeDeTime2 = Rule
    { name = "nth <time> de <time>"
    , pattern =
      [ regex "(el|la)"
      , dimension Ordinal
      , dimension Time
      , regex "de|d'"
      , dimension Time
      ]
    , prod = \case
        (_:
         Token Ordinal OrdinalData{TOrdinal.value = v}:
         Token Time td1:
         _:
         Token Time td2:
         _) -> Token Time . predNth (v - 1) False <$> intersect td2 td1
        _ -> Nothing
    }
  
  ruleDentroDeDuration :: Rule
  ruleDentroDeDuration = Rule
    { name = "dentro de <duration>"
    , pattern =
      [ regex "dintre de"
      , dimension Duration
      ]
    , prod = \case
        (_:Token Duration dd:_) ->
          Token Time <$> interval TTime.Open now (inDuration dd)
        _ -> Nothing
    }
  
  ruleWeekend :: Rule
  ruleWeekend = Rule
    { name = "week-end"
    , pattern =
      [ regex "week[ -]?end|cap de setmana"
      ]
    , prod = \_ -> tt weekend
    }
  
  ruleOrdinalQuarterYear :: Rule
  ruleOrdinalQuarterYear = Rule
    { name = "<ordinal> quarter <year>"
    , pattern =
      [ dimension Ordinal
      , Predicate $ isGrain TG.Quarter
      , regex "del? ?"
      , dimension Time
      ]
    , prod = \case
        (Token Ordinal OrdinalData{TOrdinal.value = v}:_:Token Time td:_) ->
          tt $ cycleNthAfter False TG.Quarter (v - 1) td
        _ -> Nothing
    }
  
  ruleYyyymmdd :: Rule
  ruleYyyymmdd = Rule
    { name = "yyyy-mm-dd"
    , pattern =
      [ regex "(\\d{2,4})-(0?[1-9]|1[0-2])-(3[01]|[12]\\d|0?[1-9])"
      ]
    , prod = \case
        (Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
          y <- parseInt m1
          m <- parseInt m2
          d <- parseInt m3
          tt $ yearMonthDay y m d
        _ -> Nothing
    }
  
  ruleTimeOfDayHoras :: Rule
  ruleTimeOfDayHoras = Rule
    { name = "<time-of-day> horas"
    , pattern =
      [ regex "(la | les )?"
      , Predicate isATimeOfDay
      , regex "h?\\.?(or(e|a))?s?"
      ]
    , prod = \case
        (Token Time td:_) ->
          tt $ mkLatent td
        _ -> Nothing
    }
  
  ruleElCycleAntesTime :: Rule
  ruleElCycleAntesTime = Rule
    { name = "el <cycle> antes <time>"
    , pattern =
      [ regex "(el|la|l')? ?"
      , dimension TimeGrain
      , regex "abans de"
      , dimension Time
      ]
    , prod = \case
        (_:Token TimeGrain grain:_:Token Time td:_) ->
          tt $ cycleNthAfter False grain (-1) td
        _ -> Nothing
    }
  
  ruleTwoTimeTokensSeparatedBy :: Rule
  ruleTwoTimeTokensSeparatedBy = Rule
    { name = "two time tokens separated by \",\""
    , pattern =
      [ Predicate isNotLatent
      , regex ","
      , Predicate isNotLatent
      ]
    , prod = \case
        (Token Time td1:_:Token Time td2:_) ->
          Token Time <$> intersect td1 td2
        _ -> Nothing
    }
  
  ruleMorning :: Rule
  ruleMorning = Rule
    { name = "morning"
    , pattern =
      [ regex "mat(i|í)"
      ]
    , prod = \_ ->
        let from = hour False 6
            to = hour False 12
        in Token Time . mkLatent . partOfDay <$>
             interval TTime.Open from to
    }
  
  ruleALasHourminTimeOfDay :: Rule
  ruleALasHourminTimeOfDay = Rule
    { name = "a las <hour-min>(time-of-day)"
    , pattern =
      [ regex "a (l'|les)"   -- es pot escriure a la una
      , Predicate isATimeOfDay
      , regex "horas?"
      ]
    , prod = \case
        ( _:
          x:
          _) -> Just x
        _ -> Nothing
    }
  
  -- Potser cal afegir el mateix però amb darrers
  ruleLaCyclePasado :: Rule
  ruleLaCyclePasado = Rule
    { name = "la <cycle> pasado"
    , pattern =
      [ regex "(el|els|la|les|l')?"
      , dimension TimeGrain
      , regex "passa(t|da|ts|des)"
      ]
    , prod = \case
        (_:Token TimeGrain grain:_) ->
          tt $ cycleNth grain (-1)
        _ -> Nothing
    }
  
  
  ruleYearLatent :: Rule
  ruleYearLatent = Rule
    { name = "year (latent)"
    , pattern =
        [ Predicate $ isIntegerBetween 25 10000
        ]
    , prod = \case
        (t:_) -> do
          n <- getIntValue t
          tt $ mkLatent $ year n
        _ -> Nothing
    }
  
  ruleYesterday :: Rule
  ruleYesterday = Rule
    { name = "yesterday"
    , pattern =
      [ regex "ahir"
      ]
    , prod = \_ -> tt $ cycleNth TG.Day (-1)
    }
  
  ruleDayOfWeekDayOfMonth :: Rule
  ruleDayOfWeekDayOfMonth = Rule
    { name = "<day-of-week> <day-of-month>"
    , pattern =
      [ Predicate isADayOfWeek
      , Predicate isDOMInteger
      ]
    , prod = \case
        (Token Time td:t:_) -> Token Time <$> intersectDOM td t
        _ -> Nothing
    }
  
  ruleTimeOfDayAmpm :: Rule
  ruleTimeOfDayAmpm = Rule
    { name = "<time-of-day> am|pm"
    , pattern =
      [ Predicate isATimeOfDay
      , regex "([ap])\\.?m?\\.?"
      ]
    , prod = \case
        (Token Time td:Token RegexMatch (GroupMatch (ap:_)):_) ->
          tt $ timeOfDayAMPM (Text.toLower ap == "a") td
        _ -> Nothing
    }
  
  ruleDayOfMonthDeNamedMonth :: Rule
  ruleDayOfMonthDeNamedMonth = Rule
    { name = "<day-of-month> de <named-month>"
    , pattern =
      [ Predicate isDOMInteger
      , regex "de|d'"
      , Predicate isAMonth
      ]
    , prod = \case
        (t:_:Token Time td:_) -> Token Time <$> intersectDOM td t
        _ -> Nothing
    }
  
  ruleEntreDdEtDdMonthinterval :: Rule
  ruleEntreDdEtDdMonthinterval = Rule
    { name = "entre dd et dd <month>(interval)"
    , pattern =
      [ regex "entre( el)?|des del?"
      , regex "(0?[1-9]|[12]\\d|3[01])"
      , regex "i( el)?|fins al?"
      , regex "(0?[1-9]|[12]\\d|3[01])"
      , regex "de|d'"
      , Predicate isAMonth
      ]
    , prod = \case
        (_:
         Token RegexMatch (GroupMatch (m1:_)):
         _:
         Token RegexMatch (GroupMatch (m2:_)):
         _:
         Token Time td:
         _) -> do
          v1 <- parseInt m1
          v2 <- parseInt m2
          from <- intersect (dayOfMonth v1) td
          to <- intersect (dayOfMonth v2) td
          Token Time <$> interval TTime.Closed from to
        _ -> Nothing
    }
  
  ruleNamedMonthDayOfMonth :: Rule
  ruleNamedMonthDayOfMonth = Rule
    { name = "<named-month> <day-of-month>"
    , pattern =
      [ Predicate isAMonth
      , Predicate isDOMInteger
      ]
    , prod = \case
        (Token Time td:t:_) -> Token Time <$> intersectDOM td t
        _ -> Nothing
    }
  
  ruleElTime :: Rule
  ruleElTime = Rule
    { name = "el <time>"
    , pattern =
      [ regex "d?el"
      , Predicate isNotLatent
      ]
    , prod = \case
        (_:x:_) -> Just x
        _ -> Nothing
    }
  
  ruleYear :: Rule
  ruleYear = Rule
    { name = "year"
    , pattern =
      [ Predicate $ isIntegerBetween 1000 2100
      ]
    , prod = \case
        (t:_) -> do
          v <- getIntValue t
          tt $ year v
        _ -> Nothing
    }
  
  ruleEsteenUnCycle :: Rule
  ruleEsteenUnCycle = Rule
    { name = "este|en un <cycle>"
    , pattern =
      [ regex "(aquesta?|dins (els?|la|l'|les)?)"
      , dimension TimeGrain
      ]
    , prod = \case
        (_:Token TimeGrain grain:_) ->
          tt $ cycleNth grain 0
        _ -> Nothing
    }
  
  ruleNProximasCycle :: Rule
  ruleNProximasCycle = Rule
    { name = "n proximas <cycle>"
    , pattern =
      [ Predicate $ isIntegerBetween 2 9999
      , regex "proper(a|es|s)?"
      , dimension TimeGrain
      ]
    , prod = \case
        (t:_:Token TimeGrain grain:_) -> do
          v <- getIntValue t
          tt $ cycleN True grain v
        _ -> Nothing
    }
  
  ruleLaPasadoCycle :: Rule
  ruleLaPasadoCycle = Rule
    { name = "la pasado <cycle>"
    , pattern =
      [ regex "(el|els|la|les) ?"
      , regex "passa(ts?|da|des)|darrer(a|s|es)?"
      , dimension TimeGrain
      ]
    , prod = \case
        (_:_:Token TimeGrain grain:_) ->
          tt $ cycleNth grain (-1)
        _ -> Nothing
    }
  
  ruleALasTimeOfDay :: Rule
  ruleALasTimeOfDay = Rule
    { name = "a las <time-of-day>"
    , pattern =
      [ regex "a?( las?)?|las?"
      , Predicate isATimeOfDay
      ]
    , prod = \case
        (_:Token Time td:_) ->
          tt $ notLatent td
        _ -> Nothing
    }
  
  ruleOrdinalQuarter :: Rule
  ruleOrdinalQuarter = Rule
    { name = "<ordinal> quarter"
    , pattern =
      [ dimension Ordinal
      , Predicate $ isGrain TG.Quarter
      ]
    , prod = \case
        (Token Ordinal OrdinalData{TOrdinal.value = v}:_) ->
          tt $ cycleNthAfter False TG.Quarter (v - 1) $ cycleNth TG.Year 0
        _ -> Nothing
    }
  
  ruleElCycleVinent :: Rule
  ruleElCycleVinent = Rule
    { name = "el <cycle> (proximo|que viene)"
    , pattern =
      [ regex "(el|els|la|les|l') ?"
      , dimension TimeGrain
      , regex "(vinents?)"
      ]
    , prod = \case
        (_:Token TimeGrain grain:_) ->
          tt $ cycleNth grain 1
        _ -> Nothing
    }
  
  ruleElCycleVinentTime :: Rule
  ruleElCycleVinentTime = Rule
    { name = "el <cycle> proximo|que viene <time>"
    , pattern =
      [ regex "(el|els|la|les|l') ?"
      , dimension TimeGrain
      , regex "(vinents?)"
      , dimension Time
      ]
    , prod = \case
        (_:Token TimeGrain grain:_:Token Time td:_) ->
          tt $ cycleNthAfter False grain 1 td
        _ -> Nothing
    }
  
  ruleDelMedioda :: Rule
  ruleDelMedioda = Rule
    { name = "del mediodía"
    , pattern =
      [ regex "del migdia"
      ]
    , prod = \_ ->
        let from = hour False 12
            to = hour False 17
        in Token Time . mkLatent . partOfDay <$>
             interval TTime.Open from to
    }
  
  ruleIntersectByDe :: Rule
  ruleIntersectByDe = Rule
    { name = "intersect by `de`"
    , pattern =
      [ Predicate isNotLatent
      , regex "de|d'"
      , Predicate isNotLatent
      ]
    , prod = \case
        (Token Time td1:_:Token Time td2:_) ->
          Token Time <$> intersect td1 td2
        _ -> Nothing
    }
  
  ruleTomorrow :: Rule
  ruleTomorrow = Rule
    { name = "tomorrow"
    , pattern =
      [ regex "dem(a|à)"
      ]
    , prod = \_ -> tt $ cycleNth TG.Day 1
    }
  
  ruleNthTimeDeTime :: Rule
  ruleNthTimeDeTime = Rule
    { name = "nth <time> de <time>"
    , pattern =
      [ dimension Ordinal
      , dimension Time
      , regex "de|d'"
      , dimension Time
      ]
    , prod = \case
        (Token Ordinal OrdinalData{TOrdinal.value = v}:
         Token Time td1:
         _:
         Token Time td2:
         _) -> Token Time . predNth (v - 1) False <$> intersect td2 td1
        _ -> Nothing
    }
  
  ruleTimezone :: Rule
  ruleTimezone = Rule
    { name = "<time> timezone"
    , pattern =
      [ Predicate $ and . sequence [isATimeOfDay, isNotLatent]
      , regex "\\b(YEKT|YEKST|YAKT|YAKST|WITA|WIT|WIB|WGT|WGST|WFT|WET|WEST|WAT|WAST|VUT|VLAT|VLAST|VET|UZT|UYT|UYST|UTC|ULAT|TVT|TMT|TLT|TKT|TJT|TFT|TAHT|SST|SRT|SGT|SCT|SBT|SAST|SAMT|RET|PYT|PYST|PWT|PST|PONT|PMST|PMDT|PKT|PHT|PHOT|PGT|PETT|PETST|PET|PDT|OMST|OMSST|NZST|NZDT|NUT|NST|NPT|NOVT|NOVST|NFT|NDT|NCT|MYT|MVT|MUT|MST|MSK|MSD|MMT|MHT|MDT|MAWT|MART|MAGT|MAGST|LINT|LHST|LHDT|KUYT|KST|KRAT|KRAST|KGT|JST|IST|IRST|IRKT|IRKST|IRDT|IOT|IDT|ICT|HOVT|HKT|GYT|GST|GMT|GILT|GFT|GET|GAMT|GALT|FNT|FKT|FKST|FJT|FJST|EST|EGT|EGST|EET|EEST|EDT|ECT|EAT|EAST|EASST|DAVT|ChST|CXT|CVT|CST|COT|CLT|CLST|CKT|CHAST|CHADT|CET|CEST|CDT|CCT|CAT|CAST|BTT|BST|BRT|BRST|BOT|BNT|AZT|AZST|AZOT|AZOST|AWST|AWDT|AST|ART|AQTT|ANAT|ANAST|AMT|AMST|ALMT|AKST|AKDT|AFT|AEST|AEDT|ADT|ACST|ACDT)\\b"
      ]
    , prod = \case
        (Token Time td:
         Token RegexMatch (GroupMatch (tz:_)):
         _) -> Token Time <$> inTimezone (Text.toUpper tz) td
        _ -> Nothing
    }
  
  ruleNextWeek :: Rule
  ruleNextWeek = Rule
    { name = "next week"
    , pattern =
      [ Predicate $ isGrain TG.Week
      , regex "vinent"
      ]
    , prod = \_ -> tt $ cycleNth TG.Week 1
    }
  
  rulePeriodicHolidays :: [Rule]
  rulePeriodicHolidays = mkRuleHolidays
    -- Fixed dates, year over year
    [ ( "Navidad", "(el )?nadal", monthDay 12 25)
    , ( "Dia de África", "dia de (la (libertad|liberacion) )?(á|a)frica(na)?", monthDay 5 25 )
    , ( "Dia de la Industrialización de África", "dia de (la )?industrializaci(ó|o)n de (á|a)frica(na)?", monthDay 11 20 )
    -- dates assenyalades catalanes
    , ( "Diada de Tots Sants", "((dia|diada|festivitat) de )?tots sants", monthDay 11 1 )
    , ( "Dia de difunts", "(dia|diada) de(ls)? difunts", monthDay 11 2 )
    , ( "Epifanía", "Epifania|((dia|diada) dels)? reis( mags)?( d'orient)?", monthDay 1 6 )
    , ( "Festivitat de la Purissima", "(dia|diada|festivitat) de la (purissima|immaculada) (concepci(ó|o)( de (maria|la mare de déu))?)?", monthDay 12 8 )
    , ( "Assumpció de Maria", "assumpci(ó|o) de (mar(í|i)a|la mare de déu)", monthDay 8 15 )
    , ( "Diada de Sant Jordi", "((dia|diada|festivitat) de )?sant jordi", monthDay 4 23 )
    , ( "Diada de Sant Esteve", "((dia|diada|festivitat) de )?sant esteve", monthDay 12 26 )
    , ( "Diada de Sant Joan", "((dia|diada|festivitat) de )?sant joan", monthDay 6 24 )
    , ( "Revetlla de Sant Joan", "(revetlla|nit) de sant joan", monthDay 6 23 )
    , ( "Diada de Sant Narcís", "((dia|diada|festivitat) de )?sant narc(i|í)s", monthDay 10 29 )
    , ( "Diada de Sant Josep", "((dia|diada|festivitat) de )?sant? jos(e|é)p?", monthDay 3 19 )
    , ( "Diada de la Mercè", "((dia|diada|festivitat) de )?(la mare de déu de)? la merc(è|é)", monthDay 9 24 )
    , ( "Diada de Santa Tecla", "((dia|diada|festivitat) de )?santa tecla", monthDay 9 23 )
    , ( "Diada de Sant Anastasi", "((dia|diada|festivitat) de )?sant anastasi", monthDay 5 11 )
    , ( "Diada de Montserrat", "((dia|diada|festivitat) de )?(la mare de déu de)? montserrat", monthDay 4 27 )
    -- Fi dates catalanes
    , ( "Dia dels Innocents d'Abril", "dia (dels innocents|les bromes)( d'abril)?", monthDay 4 1 )
    , ( "Dia Mundial de la Lengua Àrab", "dia mundial de la lengua (á|a)rabe", monthDay 12 18 )
    , ( "Dia de la Boxa", "(el )?dia de (la boxa|l'(B|b)oxeador)", monthDay 12 26 )
    , ( "Dia de Llengua Xinesa", "dia de llengua xinesa", monthDay 4 20 )
    --, ( "Nochebuena", "(la (cena de )?)?(nochebuena|noche buena)", monthDay 12 24 )
    , ( "Dia de Commemoració de les Víctimes de la Guerra Química", "dia (de )?(commemoratiu|conmemoraci(ó|o)) (en record )?de las v(í|i)ctimes de la guerra qu(í|i)mica", monthDay 4 29 )
    , ( "Dia de Commemoració de les Víctimes de l'Genocidi de Rwanda", "dia (de )?(commemoratiu|conmemoraci(ó|o)) (en record )?de las v(í|i)ctimes de l'genocidi de (Rw|Ru|rw|ru)anda", monthDay 4 7 )
    , ( "Dia de la Marina", "dia (de la marina|l' mar(í|i))", monthDay 6 25 )
    , ( "Dia de la Terra", "dia (internacional )?de la (mare )?terra", monthDay 4 22 )
    , ( "Dia de la Llengua Anglesa", "dia de la llengua anglesa", monthDay 4 23 )
    , ( "Les Festes de Sant Francesc d'Assís", "(les )?festes de sant (francesc d'as(í|i)s|pacho)", monthDay 10 4 )
    , ( "Dia Mundial de les Mares i dels Pares", "dia mundial de les mades y dels pares", monthDay 6 1 )
   -- , ( "Dia de Todos los Santos", "(dia|festividad) de todos los santos", monthDay 10 31 ) Tots sants és l'1 de novembre
    , ( "Dia dels Drets Humans", "dia dels drets humans", monthDay 12 10 )
    , ( "Dia Internacional de Sensibilització sobre el Albinismo", "dia internacional de sensibilitzaci(ó|o) sobre l'albinisme", monthDay 6 13 )
    , ( "Dia Internacional contra la Corrupció", "dia internacional contra la corrupci(ó|o)", monthDay 12 9 )
    , ( "Dia Internacional dels Asteroides", "dia internacional dels asteroides", monthDay 6 30 )
    , ( "Celebra el Dia Internacional de la Bisexualitat", "celebra el dia internacional de la bisexualitat", monthDay 9 23 )
    , ( "Dia Internacional de Recordación de Desastres de Txernòbil", "dia internacional de record de desastres de Txern(ò|o)bil", monthDay 4 26 )
    , ( "Dia Internacional de l'Aviació Civil", "dia internacional de l'aviaci(ó|o) civil", monthDay 12 7 )
    , ( "Dia Internacional de la Duana", "dia internacional de l(a|es) duan(a|es)", monthDay 1 26 )
    , ( "Dia Internacional de la Lluita contra l'Ús Indegut i el Tràfic Il·lícit de Drogues", "dia internacional de la lluita contra l'(ú|u)s indegut i el tr(à|a)fic il·l(í|i)cit de drogues", monthDay 6 26 )
    , ( "Dia Internacional contra els Assajos Nuclears", "dia internacional contra els assajos nuclears", monthDay 8 29 )
    , ( "Dia Internacional de la Diversitat Biològica", "dia internacional de la diversitat biol(ò|o)gica", monthDay 5 22 )
    , ( "Dia Internacional dels Monuments i Llocs", "dia internacional dels monuments i llocs", monthDay 4 18 )
    , ( "Dia Internacional per a la Prevenció de l'Explotació de l'entorn en la Guerra i els Conflictes Armats", "dia internacional per a la prevenci(ó|o) de l'explotaci(ó|o) de l'entorn a la guerra i els conflictes armats", monthDay 11 6 )
    , ( "Dia de les Nacions Unides per a la Cooperació Sud-Sud", "dia de les nacions unides per a la cooperació sud(\\-|\\s)sud", monthDay 9 12 )
    , ( "Dia Internacional per la Tolerància", "dia internacional (de|per) la toler(à|a)ncia", monthDay 11 16 )
    , ( "Dia Internacional per a l'Abolició de l'Esclavitud", "dia internacional per a l'abolici(ó|o) de l'esclavitud", monthDay 12 2 )
    , ( "Dia Internacional de l'Eliminació de la Discriminació Racial", "dia internacional de l'eliminaci(ó|o) de la discriminaci(ó|o) racial", monthDay 3 21 )
    , ( "Dia Internacional de l'Eliminació de la Violència Sexual en els Conflictes", "dia internacional de l'eliminaci(ó|o) de la viol(è|e)ncia sexual en els conflictes", monthDay 6 19 )
    , ( "Dia Internacional de l'Eliminació de la Violència contra la Dona", "dia internacional de l'eliminaci(ó|o) de la viol(è|e)ncia contra (la dona|les dones)", monthDay 11 25 )
    , ( "Dia Internacional per a l'Eradicació de la Pobresa", "dia internacional per a l'eradicaci(ó|o) de la pobresa", monthDay 10 17 )
    , ( "Dia Internacional de la Preservació de la Capa d'Ozó", "dia internacional de la preservaci(ó|o) de la capa d'oz(ó|o)", monthDay 9 16 )
    , ( "Dia Internacional de l'Record del Tràfic d'Esclaus i la seva Abolició", "dia internacional de l'record del tr(à|a)fic d'esclaus i de la seva abolici(ó|o)", monthDay 8 23 )
    , ( "Dia Internacional del Derecho a la Verdad en relación con Violaciones Graves de los Derechos Humanos y de la Dignidad de las Víctimas de las Naciones Unidas", "dia internacional del derecho a la verdad en relaci(ó|o)n con violaciones graves de los derechos humanos y de la dignidad de las v(í|i)ctimas de las naciones unidas", monthDay 3 24 )
    , ( "Dia Internacional per a l'Eliminació Total de les Armes Nuclears", "dia internacional per a l'eliminaci(ó|o) total de les armes nuclears", monthDay 9 26 )
    , ( "Dia Internacional de les Nacions Unides a Support de les Víctimes de la Tortura", "dia internacional de les Nacions Unides en support de les v(í|i)ctimes de la tortura", monthDay 6 26 )
    , ( "Dia Internacional de la Beneficència", "dia internacional de la benefic(è|e)ncia", monthDay 9 5 )
    , ( "Dia Internacional de Commemoració anual en memòria de les Víctimes de l'Holocaust", "dia internacional de commemoraci(ó|o) anual en mem(ò|o)ria de les v(í|i)ctimes de l'holocaust", monthDay 1 27 )
    , ( "Dia Internacional de la Democràcia", "dia (internacional)?de la democr(à|a)cia", monthDay 9 15 )
    , ( "Dia Internacional de les Persones amb Discapacitat", "dia internacional de les persones amb discapacitat", monthDay 12 3 )
    , ( "Dia Internacional de la Família", "dia internacional de l(a|es)? fam(í|i)li(a|es)?", monthDay 5 15 )
    , ( "Dia Internacional de les Remeses Familiars", "dia internacional de les remeses familiars", monthDay 6 16 )
    , ( "Dia Internacional dels Boscos", "dia internacional dels boscos", monthDay 3 21 )
    , ( "Dia Internacional de l'Amistat", "dia internacional de l'amistat", monthDay 7 30 )
    , ( "Dia Internacional de la Felicitat", "dia (internacional|mundial) de la felicitat", monthDay 3 20 )
    , ( "Dia Internacional dels Vols Espacials", "dia internacional (dels|del) vol(s)? espacial(s)?", monthDay 4 12 )
    , ( "Dia Internacional dels Nens Víctimes Innocents d'Agressió", "dia internacional dels nens v(í|i)ctimes innocents d'agressi(ó|o)", monthDay 6 4 )
    , ( "Dia Internacional de la no Violència", "dia internacional de la no viol(è|e)ncia", monthDay 10 2 )
    , ( "Dia Internacional de l'Nowruz", "dia internacional de l'Nowruz", monthDay 3 21 )
    , ( "Dia Internacional de la Gent Gran", "dia internacional de la gent gran", monthDay 10 1 )
    , ( "Dia Internacional de la Pau", "dia internacional de la pau", monthDay 9 21 )
    , ( "Dia Internacional de les Persones amb Discapacitat", "dia internacional de les persones amb discapacitat", monthDay 12 3 )
    , ( "Dia Internacional de Record de les Víctimes de l'Esclavitud i el Tràfic Transatlàntica d'Esclaus", "dia internacional de record de les v(í|i)ctimes de l'esclavitud i la tracta transatl(à|a)ntica d'esclaus", monthDay 3 25 )
    , ( "Dia Internacional de les Dones Rurals", "dia internacional de les dones rurals", monthDay 10 15 )
    , ( "Dia Internacional de Solidaritat amb els membres de l'Personal Detinguts o Desapareguts", "dia internacional de solidaritat amb els membres de l'personal detinguts o desapareguts", monthDay 3 25 )
    , ( "Dia Internacional de Solidaritat amb el Poble Palestí", "dia internacional de solidaritat amb el poble palestí", monthDay 11 29 )
    , ( "Dia Internacional de l'Esport per al Desenvolupament i la Pau", "dia internacional de l'esport per al desenvolupament i la pau", monthDay 4 6 )
    , ( "Dia Internacional de l'Personal de Pau de les Nacions Unides", "dia internacional de el personal de pau de les Nacions Unides", monthDay 5 29 )
    , ( "Dia Internacional de la Dona i la Nena a la Ciència", "dia internacional de la dona i la nena en la ci(è|e)ncia", monthDay 2 11 )
    , ( "Dia Internacional de l'Ioga", "dia Internacional de l'(I|i|Y|i)oga", monthDay 6 21 )
    , ( "Dia Internacional de Tolerància Zero amb la Mutilació Genital Femenina", "dia internacional de toler(à|a)ncia zero amb la mutilaci(ó|o) genital femenina", monthDay 2 6 )
    , ( "Dia Internacional de la Nena", "dia internacional de la nena", monthDay 10 11 )
    , ( "Dia Internacional de les Víctimes de Desaparicions Forçades", "dia internacional de les v(í|i)ctimes de desaparicions forçades", monthDay 8 30 )
    , ( "Dia Internacional dels Pobles Indígenes de l'Món", "dia internacional dels pobles ind(í|i)genes de l'm(ó|o)n", monthDay 8 9 )
    , ( "Dia Internacional per posar fi a la impunitat dels Crims contra Periodistes", "dia internacional per posar fi a la impunitat dels crims contra periodistes", monthDay 11 2 )
    , ( "Dia Internacional per a l'Eradicació de la Fístula Obstètrica", "dia internacional per a l'eradicaci(ó|o) de la f(í|i)stula obst(è|e)trica", monthDay 5 23 )
    , ( "Dia Internacional per a la Reducció dels Desastres Naturals", "dia internacional per a la reducci(ó|o) dels desastres (naturals)?", monthDay 10 13 )
    , ( "Dia Internacional de la Solidaritat Humana", "dia internacional de la solidaritat humana", monthDay 12 20 )
    , ( "Dia Internacional de l'Jazz", "dia internacional de jazz", monthDay 4 30 )
    , ( "Dia Internacional de l'Alfabetització", "dia internacional de l'alfabetitzaci(ó|o)", monthDay 9 8 )
    , ( "Dia Internacional de l'Home", "dia internacional de(l)? els home(s)?", monthDay 11 19 )
    , ( "Dia Internacional de l'Migrant", "dia internacional de l'migrant", monthDay 12 18 )
    , ( "Dia Internacional de la Llengua Materna", "dia (internacional|mundial) de la llengua materna", monthDay 2 21 )
    , ( "Dia Internacional de les Muntanyes", "dia internacional de les muntanyes", monthDay 12 11 )
    , ( "Dia Internacional de les Infermeres", "dia internacional de les infermeres", monthDay 5 12 )
    , ( "Dia de la Consciència Internacional sobre la Sobredosi", "dia de (la)? consciència internacional (de|sobre) la sobredosi", monthDay 8 31 )
    , ( "Dia Internacional de l'Voluntariat per al Desenvolupament Econòmic i Social", "dia internacional de l'voluntariat per al desenvolupament econ(ò|o)mic i social", monthDay 12 5 )
    , ( "Dia Internacional de les Vídues", "dia internacional de les v(í|i)dues", monthDay 6 23 )
    , ( "Dia Internacional de la Dona", "dia internacional de la dona", monthDay 3 8 )
    , ( "Dia Internacional de la Joventut", "dia internacional de la joventut", monthDay 8 12 )
    , ( "El Primer de Maig", "(el )?primer de maig", monthDay 5 1 )
    , ( "Dia Internacional de Nelson Mandela", "dia (internacional)? de nelson mandela", monthDay 7 18 )
    , ( "El Nadal Ortodoxa", "(la )?nadal ortodoxa", monthDay 1 7 )
    , ( "Any Nou Ortodox", "(l')?any (nou vell|vell ortodox|nou ortodox|nou juli(à|a))", monthDay 1 14 )
    , ( "Dia Mundial dels Serveis Públics", "dia (mundial|nacional) de(ls )?(serveis|servidor) p(ú|u)blic(s)?", monthDay 6 23 )
    , ( "Dia de Sant Patrici", "dia de sant patrici", monthDay 3 17 )
    , ( "Dia Internacional de l'Temps de l'Record i la Reconciliació per qui Van perdre la Vida durant la Segona Guerra Mundial", "dia internacional de el temps de l'record i la reconciliaci(ó|o) per als que van perdre la vida durant la segona guerra mundial", monthDay 5 8 )
    , ( "Dia de les Nacions Unides", "dia de les nacions unides", monthDay 10 24 )
    , ( "Dia Internacional d'Informació sobre el Perill de les Mines i d'Assistència per a les Activitats Relatives a les Mines", "dia internacional d'informaci(ó|o) sobre el perill de les mines i d'assist(è|e)ncia per a les activitats relatives a les mines", monthDay 4 4 )
    , ( "Dia Mundial de la Salut", "dia mundial de la salut (de les nacions unides)?", monthDay 4 7 )
    , ( "Dia Universal del Nen", "dia universal de( l'infant|l nen)", monthDay 11 20 )
    , ( "Dia de Sant Valentí", "(el )?dia de sant valent(í|i)", monthDay 2 14 )
    , ( "Dia Mundial de la lluita contra la SIDA", "dia mundial de( la lluita contra)?( la)?SIDA", monthDay 12 1 )
    , ( "Dia Mundial de Conscienciació sobre l'Autisme", "dia mundial de (la concienciaci(ó|o) sobre )?l'autismo", monthDay 4 2 )
    , ( "Dia Mundial de la Artritis Reumatoide", "dia mundial de l'artritis (reumatoide)?", monthDay 5 20 )
    , ( "Dia Mundial de l'Donant de Sang", "dia mundial de l'donant de sang", monthDay 6 14 )
    , ( "Dia Internacional de l'Llibre i de el Dret d'Autor", "dia internacional de l'libro i de( el|ls) dret(s)? d'autor", monthDay 4 23 )
    , ( "Dia Mundial de l'Braille", "dia mundial de l'braille", monthDay 1 4 )
    , ( "Dia Mundial contra el Càncer", "dia mundial contra el c(à|a)ncer", monthDay 2 4 )
    , ( "Dia Mundial de les Ciutats", "dia mundial de les ciutats", monthDay 10 31 )
    , ( "Dia Mundial de la PC", "dia mundial de la (pc|par(à|a)lisi cerebral)", monthDay 10 6 )
    , ( "Dia Mundial contra el Treball Infantil", "dia mundial contra el treball infantil", monthDay 6 12 )
    , ( "Dia Mundial contra el Tràfic de Persones", "dia mundial contra el tr(à|a)fic de persones", monthDay 7 30 )
    , ( "Dia Mundial de l'Patrimoni Audiovisual", "dia mundial (de l'|sobre el) patrimoni audiovisual", monthDay 10 27 )
    , ( "Dia Mundial de la Diversitat Cultural per al Diàleg i el Desenvolupament", "dia mundial de la diversitat cultural per al di(a|à)leg i el desenvolupament", monthDay 5 21 )
    , ( "Dia Mundial de la Seguretat i la Salut en el Treball", "dia mundial de la seguretat i la salut en el treball", monthDay 4 28 )
    , ( "Dia Mundial per l'Abolició de l'Esclavitud", "dia mundial per l'abolici(ó|o) de l'esclavitud", monthDay 12 2 )
    , ( "Dia Mundial de la Justícia Social", "dia mundial de la just(í|i)cia social", monthDay 2 20 )
    , ( "Dia Mundial de l'Malalt", "dia mundial (de l'|dels) malalts", monthDay 2 11 )
    , ( "Dia Mundial de Lluita contra la Desertificació i la Sequera", "dia mundial (de lluita contra|per combatre) la desertificaci(ó|o) i la sequera", monthDay 6 17 )
    , ( "Dia Mundial d'Informació sobre el Desenvolupament", "dia mundial d'informaci(ó|o) sobre el desenvolupament", monthDay 10 24 )
    , ( "Dia Mundial de la Diabetis", "dia mundial de la diabetis", monthDay 11 14 )
    , ( "Dia Mundial de la Síndrome de Down", "dia mundial de la s (í|i)ndrome de Down", monthDay 3 21 )
    , ( "Dia Mundial de Presa de Consciència de l'Abús i Maltractament en la Vellesa", "dia mundial de presa de consci(è|e)ncia de l'ab(ú|u)s i maltractament en la vellesa", monthDay 6 15 )
    , ( "Dia Mundial de l'Medi Ambient", "dia mundial de l'(entorn|medi ambient)", monthDay 6 5 )
    , ( "Dia Mundial de l'Alimentació", "dia mundial de l'alimentaci(ó|o)", monthDay 10 16 )
    , ( "Dia per a la Commemoració i Dignificació de les Víctimes de l'Crim de Genocidi i per a la seva prevenció", "dia per a la commemoraci(ó|o) i dignificaci(ó|o) de les v(í|i)ctimes de l'crim de genocidi i per a la seva prevenci(ó|o)", monthDay 12 9 )
    , ( "Dia Mundial de l'Cor", "dia mundial de l'cor", monthDay 9 29 )
    , ( "Dia Mundial de l'Hepatitis", "dia mundial (contra|de) l'hepatitis", monthDay 7 28 )
    , ( "Dia Mundial de l'Assistència Humanitària", "dia mundial de l'assist(è|e)ncia humanit(à|a)ria", monthDay 8 19 )
    , ( "Dia Internacional de la Societat de la Informació", "dia (internacional|mundial) de (les telecomunicacions i)? la societat de la informaci(ó|o)", monthDay 5 17 )
    , ( "Dia Mundial de la Propietat Intel·lectual", "dia mundial de la propietat intel·lectual", monthDay 4 26 )
    , ( "Dia Mundial de la Malària", "dia mundial de la mal(à|a)ria", monthDay 4 25 )
    , ( "Dia Mundial de la Salut Mental", "dia mundial de la salut mental", monthDay 10 10 )
    , ( "Dia Mundial de la Meteorologia", "dia (mundial de (la )?meteorologia|meteorol(ò|o)gic mundial)", monthDay 3 23 )
    , ( "Dia Mundial sense Tabac", "dia mundial sense tabac", monthDay 5 31 )
    , ( "Dia Mundial dels Oceans", "dia mundial dels oceans", monthDay 6 8 )
    , ( "Dia Mundial de l'Càncer de Ovari", "dia mundial de l'c(à|a)ncer d'ovari", monthDay 5 8 )
    , ( "Dia Mundial contra la Pneumònia", "dia mundial contra la pneum(ò|o)nia", monthDay 11 12 )
    , ( "Dia Mundial de la Poesia", "dia mundial de la poesia", monthDay 3 21 )
    , ( "Dia Mundial de la Població", "dia mundial de la poblaci(ó|o)", monthDay 7 11 )
    , ( "Dia Mundial del Correo", "Dia Mundial de l'Correu", monthDay 10 9 )
    , ( "Dia de la Prematuridad Mundial", "dia (de la prematuritat mundial|mundial de l'infant prematur)", monthDay 11 17 )
    , ( "Dia Mundial de la Llibertat de Premsa", "dia mundial de la llibertat de premsa", monthDay 5 3 )
    , ( "Dia Mundial contra la Ràbia", "dia mundial (contra | de) la r(à|a)bia", monthDay 9 28 )
    , ( "Dia Mundial de la Ràdio", "dia mundial de la r(à|a)dio", monthDay 2 13 )
    , ( "Dia Mundial dels Refugiats", "dia mundial (de l'|dels) refugiat(s)?", monthDay 6 20 )
    , ( "Dia Mundial de la Ciència per la Pau i el Desenvolupament", "dia mundial de la ci(è|e)ncia per a la pau i el desenvolupament", monthDay 11 10 )
    , ( "Dia Mundial de la Salut Sexual", "dmss|dia mundial de la salut sexual", monthDay 9 4 )
    , ( "Dia Mundial de l'Sòl", "dia mundial de terra", monthDay 12 5 )
    , ( "Dia Mundial de l'Accident Cerebrovascular", "dia mundial del (accident cerebrovascular|acv)", monthDay 10 29 )
    , ( "Dia Mundial per a la Prevenció de l'Suïcidi", "dia mundial per a la prevenci(ó|o)de l'su(ï|i)cidi", monthDay 9 10 )
    , ( "Dia Mundial dels Docents", "dia mundial (dels docents|de l'mestre)", monthDay 10 5 )
    , ( "Dia Mundial de la Televisió", "dia mundial de la televisi(ó|o)", monthDay 11 21 )
    , ( "Dia Mundial de l'bany", "dia mundial del (lavabo|v(à|a)ter)", monthDay 11 19 )
    , ( "Dia Mundial de l'Turisme", "dmt|dia mundial de l'turisme", monthDay 9 27 )
    , ( "Dia Mundial de la Tuberculosi", "dia mundial de (lluita contra)?la (tuberculosi|tb)", monthDay 3 24 )
    , ( "Dia Mundial de la Tonyina", "dia mundial de la tonyina", monthDay 5 2 )
    , ( "Dia Mundial del Veganismo", "dia mundial del veganismo", monthDay 11 1 )
    , ( "Dia Mundial del Vegetarianismo", "dia mundial del vegetarianismo", monthDay 10 1 )
    , ( "Dia Mundial del Agua", "dia mundial del agua", monthDay 3 22 )
    , ( "Dia Mundial de les Zones Humides", "dia mundial de les zones humides", monthDay 2 2 )
    , ( "Dia Mundial de la Vida Silvestre", "dia mundial de la vida silvestre", monthDay 3 3 )
    , ( "Dia Mundial de les Habilitats de la Joventut", "dia mundial de les habilitats de la joventut", monthDay 7 15 )
    , ( "Dia de la Zero Discriminació", "dia de la zero discriminació", monthDay 3 1 )
  
    -- Fixed day/week/month, year over year
    , ( "Dia de la Commonwealth", "dia de la commonwealth", nthDOWOfMonth 2 1 3 )
    , ( "Dia Mundial en Record de les Víctimes d'Accidents de Trànsit"
      , "dia (mundial )?en recor de las v(í|i)ctimes (d'accidents )?de tr(à|a)nsit"
      , nthDOWOfMonth 3 7 11 )
    , ( "Dia Internacional de les Cooperatives"
      , "dia internacional de les cooperatives", nthDOWOfMonth 1 6 7 )
    , ( "Dia de Martin Luther King"
      , "(MLK|dia de Martin Luther King,?)( Jr\\.?| J(ú|u)nior)?|dia dels drets humans a Idaho"
      , nthDOWOfMonth 3 1 1
      )
  
    -- The day after Thanksgiving (not always the fourth Friday of November)
    , ( "Divendres negre", "divendres negre|black( |-)?friday"
      , cycleNthAfter False TG.Day 1 $ nthDOWOfMonth 4 4 11
      )
    , ( "Dia Mundial de l'Hàbitat", "dia mundial de l'h(à|a)bitat", nthDOWOfMonth 1 1 10 )
    , ( "Dia Mundial de l'Ronyó", "dia mundial de l'rony(ó|o)", nthDOWOfMonth 2 4 3 )
    , ( "Dia Mundial de la Lepra", "dia mundial (contra|de) la lepra"
      , predLastOf (dayOfWeek 7) (month 1) )
    , ( "Dia Marítim Mundial", "dia mar(í|i)tim mundial"
      , predLastOf (dayOfWeek 4) (month 9) )
    , ( "Dia Mundial de les Aus Migratòries", "dia mundial de les aus migrat(ò|o)ries"
      , nthDOWOfMonth 2 6 5 )
    , ( "Dia mundial de la filosofia", "Dia mundial de la filosofia", nthDOWOfMonth 3 4 11 )
    , ( "Dia mundial de la religió", "dia mundial de (la|les)? religi(ó|ons)", nthDOWOfMonth 3 7 1 )
    , ( "Dia mundial de la vista", "dia mundial de la (vista|visi(ó|o))", nthDOWOfMonth 2 4 10 )
  
    -- Other
    , ( "Dia de el cap", "(el )?dia (nacional )?de el cap", predNthClosest 0 weekday (monthDay 10 16) )
    ]
  
  ruleElDayOfMonthNonOrdinalWithDia :: Rule
  ruleElDayOfMonthNonOrdinalWithDia = Rule
    { name = "dia <day-of-month> (non ordinal)"
    , pattern =
      [ regex "dia"
      , Predicate $ isIntegerBetween 1 31
      ]
    , prod = \case
        (_:t:_) -> do
          v <- getIntValue t
          tt $ dayOfMonth v
        _ -> Nothing
    }
  
  ruleNextWeekAlt :: Rule
  ruleNextWeekAlt = Rule
    { name = "next week (alt)"
    , pattern =
      [ regex "proper(a|s|es)|següents?"
      , Predicate $ isGrain TG.Week
      ]
    , prod = \_ -> tt $ cycleNth TG.Week 1
    }
  
  
  -- vaig per aquí
  ruleYearByAddingThreeNumbers :: Rule
  ruleYearByAddingThreeNumbers = Rule
    { name    = "year (value by adding three composing numbers together)"
    , pattern =
      [ regex "mil"
      , Predicate $ isIntegerBetween 100 1000
      , Predicate $ isIntegerBetween 1 100
      ]
    , prod    = \case
        (_:t1:t2:_) -> do
          v1 <- getIntValue t1
          v2 <- getIntValue t2
          tt $ year $ 1000 + v1 + v2
        _ -> Nothing
    }
  
  rules :: [Rule]
  rules =
    [ ruleALasHourminTimeOfDay
    , ruleALasTimeOfDay
    , ruleAfternoon
    , ruleAnoNuevo
    , ruleCeTime
    , ruleDatetimeDatetimeInterval
    , ruleDayOfMonthSt
    , ruleDayOfMonthDeNamedMonth
    , ruleDayOfWeekDayOfMonth
    , ruleDdddMonthinterval
    , ruleDdmm
    , ruleDdmmyyyy
    , ruleDeDatetimeDatetimeInterval
    , ruleElCycleVinentTime
    , ruleDelMedioda
    , ruleDelYear
    , ruleDentroDeDuration
    , ruleElCycleAntesTime
    , ruleElCycleVinent
    , ruleElCycleVinent
    , ruleElDayOfMonthDeNamedMonth
    , ruleElDayOfMonthNonOrdinal
    , ruleElProximoCycle
    , ruleElTime
    , ruleEnDuration
    , ruleEntreDatetimeEtDatetimeInterval
    , ruleEntreDdEtDdMonthinterval
    , ruleEsteenUnCycle
    , ruleEvening
    , ruleHaceDuration
    , ruleHhhmmTimeOfDay
    , ruleHourOfDayMigQuart
    , ruleHourOfDayUnQuart
    , ruleHourOfDayUnQuartiCinc
    , ruleHourOfDayUnQuartiMig
    , ruleHourOfDayUnQuartiDeu
    , ruleHourOfDayDosQuarts
    , ruleHourOfDayDosQuartsiCinc
    , ruleHourOfDayDosQuartsiMig
    , ruleHourOfDayDosQuartsiDeu
    , ruleHourOfDayTresQuarts
    , ruleHourOfDayTresQuartsiCinc
    , ruleHourOfDayTresQuartsiMig
    , ruleHourOfDayTresQuartsiDeu
    , ruleHourOfDayAndRelativeMinutes
    , ruleHourOfDayIntegerAsRelativeMinutes
    , ruleIntersect
    , ruleIntersectByDe
    , ruleLaCyclePasado
    , ruleLaPasadoCycle
    , ruleMatinada
    , ruleNit
    , ruleMigdia
    , ruleMidnight
    , ruleMorning
    , rulePODIn
    , rulePODThis
    , ruleTODPOD
    , ruleNCycleVinent
    , ruleNPasadosCycle
    , ruleNProximasCycle
    , ruleNamedMonthDayOfMonth
    , ruleNamedMonthNamedDayNext
    , ruleNamedMonthNamedDayPast
    , ruleNamedMonthNamedDayPast2
    , ruleNochevieja
    , ruleNoon
    , ruleToday
    , ruleNthTimeDeTime
    , ruleNthTimeDeTime2
    , ruleOrdinalQuarter
    , ruleOrdinalQuarterYear
    , rulePasadosNCycle
    , ruleProximasNCycle
    , ruleRightNow
    , ruleTheDayAfterTomorrow
    , ruleTheDayBeforeYesterday
    , ruleThisDayofweek
    , ruleTimeOfDayAmpm
    , ruleTimeOfDayHoras
    , ruleTimeOfDayLatent
    , ruleTomorrow
    , ruleTwoTimeTokensSeparatedBy
    , ruleUltimoDayofweekDeTime
    , ruleWeekend
    , ruleYear
    , ruleYearLatent
    , ruleYesterday
    , ruleYyyymmdd
    , ruleHourOfDayAndThreeQuarter
    , ruleHourOfDayAndHalf
    , ruleHourOfDayAndQuarter
    , ruleHourOfDayAndRelativeMinutes2
    , ruleHourOfDayThreeQuarter
    , ruleHourOfDayHalf
    , ruleHourOfDayQuarter
    , ruleHourOfDayIntegerAsRelativeMinutes2
    , ruleTimezone
    , ruleElDayOfMonthNonOrdinalWithDia
    , ruleNextWeek
    , ruleNextWeekAlt
    , ruleYearByAddingThreeNumbers
    , ruleDurationIn
    , ruleDurationAgo
    ]
    ++ ruleDaysOfWeek
    ++ ruleMonths
    ++ ruleSeasons
    ++ rulePeriodicHolidays
  