text:
<?php

$config = array(

    #"identifier"          => "yourserver.uri.com",
    "name"                => "Name of your service",
    "auth.protocol"       => "tiqrauth",	# protocol compiled into app
    "enroll.protocol"     => "tiqrenroll",	# enroll protocol compiled in to app

    "ocra.suite"          => "OCRA-1:HOTP-SHA1-6:QH10-S",

    "logoUrl"             => "https://demo.tiqr.org/img/tiqrRGB.png",	# change to your idp logo URL
    "infoUrl"             => "https://tiqr.org",			# change to your info page URL

    "tiqr.path"           => "../vendor/tiqr/tiqr-server-libphp/library/tiqr",

    "phpqrcode.path"      => "../vendor/kairos/phpqrcode",

    "zend.path"           => "../vendor/zendframework/zendframework1/library",

    "apns.certificate"    => "../certificates/your_apple_push_notification_certificate.pem",
    "apns.environment"    => "sandbox",

    "gcm.application"     => "com.example.authenticator",
    "gcm.apikey"          => "your GCM api key",

    // blocks configuration
    "maxAttempts"            => 3, // maximum number of login attempts before a block is set, set to 0 for not using blocks at all
    "temporaryBlockDuration" => 0, // duration of temporary block in minutes, set to 0 for no blocks or permanent blocks only
    "maxTemporaryBlocks"     => 0, // defines number of temporary blocks before setting a permanent block, set to anything other then 0 for using temporary and permanent blocks

    "statestorage"        => array("type" => "file"),
    // "statestorage"        => array( "type" => "pdo",
    //                                 "table" => "tiqrstate",
    //                                 "dsn" => "mysql:dbname=tiqr;host=mysql.surfnet.nl",
    //                                 "username" => "tiqr",
    //                                 "password" => "*****"),

    "devicestorage"       => array("type"  => "tokenexchange",
                                   "url"   => "http://path/to/your/tokenexchange/server/",
                                   "appid" => "idOfYourApp"),

    "userstorage"         => array("type" => "file", "path" => "/tmp", "encryption" => array('type' => 'dummy')),

    // "userstorage"         =>  array("type" => "ldap",
    //                                 "encryption" => array('type' => 'dummy')
    //                                 "host" => "ldap.surfnet.nl",
    //                                 "username" => "cn=Admin,ou=Persons,ou=Office,dc=SURFnet,dc=NL",
    //                                 "password" => "*****",
    //                                 "bindRequiresDn" => true,
    //                                 "accountDomainName" => "surfnet.nl",
    //                                 "baseDn" => "dc=surfnet,dc=nl",
    //                                 "userClass" => 'organizationalPerson',
    //                                 "dnPattern" =>  "cn=%s,ou=Persons,ou=Office,dc=surfnet,dc=nl",
    //                                 "idAttr" => 'cn',
    //                                 "displayNameAttr" => 'cn',
    //                                 "notificationTypeAttr" => 'tiqrNotificationType',
    //                                 "notificationAddressAttr" => 'tiqrNotificationAddress',
    //                                 "secretAttr" => 'tiqrSecret',
    //                                 "isBlockedAttr" => 'tiqrIsBlocked',
    //                                 "loginAttemptsAttr" => 'tiqrLoginAttempts',
    //                          ),

    // "userstorage"       => array("type" => "pdo",
    //                              "table" => "tiqruser",
    //                              "dsn" => "mysql:dbname=tiqr;host=mysql.surfnet.nl",
    //                              "username" => "tiqr",
    //                              "password" => "*****"),

    // secretstore can de defined to store user shared secrets separately
    // same as userstorage, but also possible to use an external oath service for storage
    // "usersecretstorage"   => array("type" => "file", "path" => "../../users/secrets"),

    // "usersecretstorage"   =>  array("type" => "ldap",
    //                                 "host" => "ldap.surfnet.nl",
    //                                 "username" => "cn=Admin,ou=Persons,ou=Office,dc=SURFnet,dc=NL",
    //                                 "password" => "*****",
    //                                 "bindRequiresDn" => true,
    //                                 "accountDomainName" => "surfnet.nl",
    //                                 "baseDn" => "dc=surfnet,dc=nl",
    //                                 "userClass" => 'organizationalPerson',
    //                                 "dnPattern" =>  "cn=%s,ou=Persons,ou=Office,dc=surfnet,dc=nl",
    //                                 "idAttr" => 'cn',
    //                                 "secretAttr" => 'tiqrSecret',
    //                          ),

    // "usersecretstorage" => array("type" => "pdo",
    //                              "table" => "tiqrusersecret",
    //                              "dsn" => "mysql:dbname=tiqr;host=mysql.surfnet.nl",
    //                              "username" => "tiqr",
    //                              "password" => "*****"),

    // if you use this, the oathservice will also be used to generate ocra challenges and validate them
    //"usersecretstorage"   => array("type" => "oathserviceclient",
    //                               "apiURL" => "http://example.com/",
    //                               "consumerKey" => "43290843902890"),

);


text:
layout: page
title: Lotus Foundation Party
date: 2016-05-24
author: Olivia Silva
tags: weekly links, java
status: published
summary: Duis facilisis bibendum condimentum. Vestibulum scelerisque a nisl.
banner: images/banner/leisure-05.jpg
booking:
  startDate: 11/16/2018
  endDate: 11/21/2018
  ctyhocn: ATSJJHX
  groupCode: LFP
published: true
---
Donec placerat mi non eros pretium dignissim. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus laoreet est a ultrices gravida. Phasellus at tortor ut magna viverra pellentesque. Integer mauris eros, interdum ac arcu et, lacinia tincidunt enim. Nunc sed dapibus odio, et posuere sem. Suspendisse aliquet metus non velit elementum, vel volutpat elit venenatis. In malesuada ac tortor sit amet varius. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum lacinia vulputate vulputate. Maecenas non mattis leo. Pellentesque sed velit quis augue consequat bibendum ut ac quam.
Morbi pellentesque convallis lacus at tempor. In ac dictum eros. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vestibulum nisl non enim malesuada bibendum. Nullam ac risus eget est tempor vulputate. Sed suscipit risus at lorem bibendum gravida. Maecenas in sapien non quam pharetra vestibulum. Vivamus est augue, cursus viverra mollis accumsan, pretium ultricies tortor. Proin dapibus, elit et tempus venenatis, lacus mi porta purus, in aliquet augue eros sed quam. Mauris viverra bibendum turpis.

1 Sed interdum purus sit amet mi venenatis vestibulum
1 Morbi vel velit semper, condimentum sapien nec, egestas nisl.

Aliquam ultricies quam risus, eu volutpat elit dapibus et. Donec non pharetra turpis, vitae posuere diam. In vitae nisl aliquet, molestie augue eget, posuere felis. Sed sed ullamcorper eros, a tempus lectus. Etiam malesuada urna at est accumsan mollis. Nunc luctus mi velit, in sodales nibh fermentum sagittis. Maecenas ut accumsan augue, et laoreet lacus. Morbi nunc enim, congue sit amet malesuada vitae, hendrerit eget magna. Proin faucibus congue erat ut rhoncus. Mauris bibendum magna nunc, eu pulvinar tellus dignissim ac.

redpajama_set_name: RedPajamaGithub


text:
from msrest.serialization import Model

class ClusterHealthChunkQueryDescription(Model):
    """The cluster health chunk query description, which can specify the health
    policies to evaluate cluster health and very expressive filters to select
    which cluster entities to include in response.

    :param node_filters: Defines a list of filters that specify which nodes to
     be included in the returned cluster health chunk.
     If no filters are specified, no nodes are returned. All the nodes are used
     to evaluate the cluster's aggregated health state, regardless of the input
     filters.
     The cluster health chunk query may specify multiple node filters.
     For example, it can specify a filter to return all nodes with health state
     Error and another filter to always include a node identified by its
     NodeName.
    :type node_filters: list of :class:`NodeHealthStateFilter
     <azure.servicefabric.models.NodeHealthStateFilter>`
    :param application_filters: Defines a list of filters that specify which
     applications to be included in the returned cluster health chunk.
     If no filters are specified, no applications are returned. All the
     applications are used to evaluate the cluster's aggregated health state,
     regardless of the input filters.
     The cluster health chunk query may specify multiple application filters.
     For example, it can specify a filter to return all applications with
     health state Error and another filter to always include applications of a
     specified application type.
    :type application_filters: list of :class:`ApplicationHealthStateFilter
     <azure.servicefabric.models.ApplicationHealthStateFilter>`
    :param cluster_health_policy:
    :type cluster_health_policy: :class:`ClusterHealthPolicy
     <azure.servicefabric.models.ClusterHealthPolicy>`
    :param application_health_policies:
    :type application_health_policies: :class:`ApplicationHealthPolicies
     <azure.servicefabric.models.ApplicationHealthPolicies>`
    """

    _attribute_map = {
        'node_filters': {'key': 'NodeFilters', 'type': '[NodeHealthStateFilter]'},
        'application_filters': {'key': 'ApplicationFilters', 'type': '[ApplicationHealthStateFilter]'},
        'cluster_health_policy': {'key': 'ClusterHealthPolicy', 'type': 'ClusterHealthPolicy'},
        'application_health_policies': {'key': 'ApplicationHealthPolicies', 'type': 'ApplicationHealthPolicies'},
    }

    def __init__(self, node_filters=None, application_filters=None, cluster_health_policy=None, application_health_policies=None):
        self.node_filters = node_filters
        self.application_filters = application_filters
        self.cluster_health_policy = cluster_health_policy
        self.application_health_policies = application_health_policies


text:
from flask import Module, url_for, \
    redirect, g, flash, request, current_app

# from flaskext.mail import Message
from flaskext.babel import gettext as _

from newsmeme.models import Post, Tag
from newsmeme.extensions import mail, db
from newsmeme.helpers import render_template, cached
from newsmeme.forms import PostForm, ContactForm
from newsmeme.decorators import keep_login_url
from newsmeme.permissions import auth

frontend = Module(__name__)

@frontend.route("/")
@frontend.route("/<int:page>/")
@cached()
@keep_login_url
def index(page=1):

    page_obj = Post.query.popular().hottest().restricted(g.user).as_list().\
                          paginate(page, per_page=Post.PER_PAGE)

    page_url = lambda page: url_for("frontend.index", page=page)

    return render_template("index.html",
                           page_obj=page_obj,
                           page_url=page_url)

@frontend.route("/latest/")
@frontend.route("/latest/<int:page>/")
@cached()
@keep_login_url
def latest(page=1):

    page_obj = Post.query.popular().restricted(g.user).as_list().\
                          paginate(page, per_page=Post.PER_PAGE)

    page_url = lambda page: url_for("frontend.latest", page=page)

    return render_template("latest.html",
                           page_obj=page_obj,
                           page_url=page_url)

@frontend.route("/deadpool/")
@frontend.route("/deadpool/<int:page>/")
@cached()
@keep_login_url
def deadpool(page=1):

    page_obj = Post.query.deadpooled().restricted(g.user).as_list().\
                          paginate(page, per_page=Post.PER_PAGE)

    page_url = lambda page: url_for("frontend.deadpool", page=page)

    return render_template("deadpool.html",
                           page_obj=page_obj,
                           page_url=page_url)

@frontend.route("/submit/", methods=("GET", "POST"))
@auth.require(401)
def submit():

    form = PostForm()

    if form.validate_on_submit():

        post = Post(author=g.user)
        form.populate_obj(post)

        db.session.add(post)
        db.session.commit()

        flash(_("Thank you for posting"), "success")

        return redirect(url_for("frontend.latest"))

    return render_template("submit.html", form=form)

@frontend.route("/search/")
@frontend.route("/search/<int:page>/")
@keep_login_url
def search(page=1):

    keywords = request.args.get("keywords", '').strip()

    if not keywords:
        return redirect(url_for("frontend.index"))

    page_obj = Post.query.search(keywords).restricted(g.user).as_list().\
                          paginate(page, per_page=Post.PER_PAGE)

    if page_obj.total == 1:

        post = page_obj.items[0]
        return redirect(post.url)

    page_url = lambda page: url_for('frontend.search',
                                    page=page,
                                    keywords=keywords)

    return render_template("search.html",
                           page_obj=page_obj,
                           page_url=page_url,
                           keywords=keywords)

@frontend.route("/contact/", methods=("GET", "POST"))
@keep_login_url
def contact():

    if g.user:
        form = ContactForm(name=g.user.username,
                           email=g.user.email)

    else:
        form = ContactForm()

    if form.validate_on_submit():

        admins = current_app.config.get('ADMINS', [])

        from_address = "%s <%s>" % (form.name.data,
                                    form.email.data)

        if admins:
            message = Message(subject=form.subject.data,
                              body=form.message.data,
                              recipients=admins,
                              sender=from_address)

            mail.send(message)

        flash(_("Thanks, your message has been sent to us"), "success")

        return redirect(url_for('frontend.index'))

    return render_template("contact.html", form=form)

@frontend.route("/tags/")
@cached()
@keep_login_url
def tags():
    tags = Tag.query.cloud()
    return render_template("tags.html", tag_cloud=tags)

@frontend.route("/tags/<slug>/")
@frontend.route("/tags/<slug>/<int:page>/")
@cached()
@keep_login_url
def tag(slug, page=1):
    tag = Tag.query.filter_by(slug=slug).first_or_404()

    page_obj = tag.posts.restricted(g.user).as_list().\
                    paginate(page, per_page=Post.PER_PAGE)

    page_url = lambda page: url_for('frontend.tag',
                                    slug=slug,
                                    page=page)

    return render_template("tag.html",
                           tag=tag,
                           page_url=page_url,
                           page_obj=page_obj)

@frontend.route("/help/")
@keep_login_url
def help():
    return render_template("help.html")

@frontend.route("/rules/")
@keep_login_url
def rules():
    return render_template("rules.html")


text:
@interface FLObservableTests : FLCoreFrameworkTest

@end


text:
class AchievementEvt {
    constructor(subType, payload) {
        this.type = 'achievements';
        this.subType = subType;
        this.payload = payload;
    }
};

/**
 * generate PageVisitEvt
 * @param {string}
 * @returns {AchievementEvt}
 */
export class PageVisitEvt extends AchievementEvt {
    constructor(pageName) {
        super('page-visited', pageName);
    }
};

/**
 * generate ForgotPasswordEvt
 * @param {String} targetEmail
 * @returns {AchievementEvt}
 */
export class ForgotPasswordEvt extends AchievementEvt {
    constructor(targetEmail) {
        super('forgot-password', targetEmail);
    }
};

/**
 * generate ForgotPasswordEvt
 * @returns {AchievementEvt}
 */
export class MoodRegisteredEvt extends AchievementEvt {
    constructor() {
        super('mood-registered');
    }
};

/**
 * generate TimeTravelEvt
 * @param {Object} targetRange
 * @returns {AchievementEvt}
 */
export class TimeTravelEvt extends AchievementEvt {
    constructor(targetRange) {
        super('time-travel', targetRange);
    }
};

// TODO
// clickedOnNotification from SW - just after action [fast hand, tchin tchin, chain reaction]
// ensure all ui event are processed - OK [mood entry, page visits, past, future, forgot password] await TEST [duck face] KO [duck face]
// snackbar for achievements + animation

const badgesConfig = {
    badgesArray: [
        { title: 'adventurer', description: 'visited all pages in one session', badge: 'adventurer' },
        { title: 'lost in translation', description: 'went to 404 page', badge: 'lost-in-translation' },
        { title: 'duck face', description: 'got a custom avatar', badge: 'no-more-faceless' },
        { title: 'goldfish', description: 'forgot password mechanism activated X1', badge: 'goldfish' },
        { title: 'alzeihmer', description: 'forgot password mechanism activated X3', badge: '019-grandfather' },
        { title: 'mood alert', description: 'subscribed for notifications', badge: '003-smartphone' },
        { title: 'mood monitor', description: 'multiple subscriptions for notifications', badge: '010-technology' },
        { title: 'fast hand', description: 'clicked on notification', badge: 'fast-hand' },
        { title: 'tchin tchin', description: 'your mood update notification nudged someone else mood update', badge: '001-toast' },
        { title: 'chain reaction', description: 'your mood update notification nudged two persons to update their mood', badge: '007-share' },
        { title: 'back to the future', description: 'time traveled more than one month in the past', badge: 'back-to-the-future' },
        { title: 'fortuneteller', description: 'tried to time travel more than a month in the future. Tip: it is useless!', badge: '010-crystal-ball' },
        { title: 'noob moodist', description: 'first mood update', badge: '014-helmet' },
        { title: 'baron moodist', description: 'updated mood three days straight', badge: '011-crown-2' },
        { title: 'duke moodist', description: 'updated mood a full week straight', badge: '012-crown-1' },
        { title: 'archduke moodist', description: 'updated mood a full month straight', badge: '010-crown-3' },
        { title: 'king moodist', description: 'updated mood three months straight', badge: '013-crown' },
        { title: 'emperor moodist', description: 'updated mood a full year straight', badge: '003-greek' },
        { title: 'happy days', description: 'positive mood for the last five updates', badge: '005-heavy-metal' },
        { title: 'depression', description: 'negative mood for the last five updates', badge: '006-crying' },
        { title: 'zen & balanced', description: 'neurtral mood for the last three updates', badge: '003-libra' },
        { title: 'mood roller coaster', description: 'changed mood from positive to negative, or reverse, in one day', badge: '005-roller-coaster' },
        { title: 'mood swings meds', description: 'changed mood more than three times a day', badge: '008-pills' },
        { title: 'blissed', description: 'mood updated to highest possible score', badge: '004-island' },
        { title: 'suicidal tendencies', description: 'mood updated to lowest possible score', badge: '006-gallows' },
        { title: 'come back', description: 'from negative to positive mood', badge: '005-profits' },
        { title: 'mood swing', description: 'from positive to negative mood', badge: '004-loss' },
        { title: 'stairway to heaven', description: 'mood increased 5 scores at once', badge: '015-paper-plane' },
        { title: 'nuclear disaster', description: 'mood decreased 5 scores at once', badge: '007-bomb-detonation' }
    ],
    AchievementsEvts: {
        PageVisitEvt: PageVisitEvt,
        ForgotPasswordEvt: ForgotPasswordEvt,
        TimeTravelEvt: TimeTravelEvt,
        MoodRegisteredEvt: MoodRegisteredEvt
    },
    technical: {
        gravatarImagesCacheName: '$$$toolbox-cache$$$https://moodies-1ad4f.firebaseapp.com/$$$',
        adventurerPageList: ['home', 'profile', 'users', 'mood-input', 'time-travel', 'about', 'badges'],
        adventurerID: 'adventurer',
        lostInTranslationPageList: ['404'],
        lostInTranslationID: 'lost in translation',
        backToTheFutureID: 'back to the future',
        fortunetellerID: 'fortuneteller',
        alzeihmerGoldfishID: 'forgotPasswordCounter',
        duckFaceID: 'duck face',
        moodsRelatedAchievementsSpecialEvt: 'all-moods-related-achievements'
    }
};

export default badgesConfig;


text:
import MaxLenModule from './news-len.filter';

describe('MaxLenFilter', () => {
  const MAX_LEN = 15;
  let maxLenFun;

  beforeEach(angular.mock.module(MaxLenModule));

  beforeEach(
    angular.mock.inject((maxLenFilter) => {
      maxLenFun = maxLenFilter;
    }));

  it('leaves "lorem ipsum" unchanged', () => {
    expect(maxLenFun('lorem ipsum', MAX_LEN)).toBe('lorem ipsum');
  });

  it('transforms "abcdefg hijklmnop" to "abcdefg hijklmn..."', () => {
    expect(maxLenFun('abcdefg hijklmnop', MAX_LEN)).toBe('abcdefg hijklmn...');
  });

  it('leaves "" unchanged', () => {
    expect(maxLenFun('', MAX_LEN)).toBe('');
  });

  it('transforms "a" to "..."', () => {
    const maxLen = 0;
    expect(maxLenFun('a', maxLen)).toBe('...');
  })

  it('transforms "                     " to "               ..."', () => {
    expect(maxLenFun('                     ', MAX_LEN)).toBe('               ...');
  });
});


text:
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Globalization;
using namespace Windows::Globalization::DateTimeFormatting;
using namespace Windows::UI::Xaml;

namespace winrt::SDKTemplate::implementation
{
    Scenario3_Enum::Scenario3_Enum()
    {
        InitializeComponent();
    }

    void Scenario3_Enum::ShowResults_Click(IInspectable const&, RoutedEventArgs const&)
    {
        // This scenario uses the Windows.Globalization.Calendar class to enumerate through a calendar and
        // perform calendar math
        std::wostringstream results;

        results <<
            L"The number of years in each era of the Japanese era calendar is not regular. " <<
            L"It is determined by the length of the given imperial era:\n";

        // Create Japanese calendar.
        Calendar calendar({ L"en-US" }, CalendarIdentifiers::Japanese(), ClockIdentifiers::TwentyFourHour());

        // Enumerate all supported years in all supported Japanese eras.
        for (calendar.Era(calendar.FirstEra()); true; calendar.AddYears(1))
        {
            // Process current era.
            results << L"Era " << std::wstring_view(calendar.EraAsString()) <<
                L" contains " << calendar.NumberOfYearsInThisEra() <<
                L" year(s)\n";

            // Enumerate all years in this era.
            for (calendar.Year(calendar.FirstYearInThisEra()); true; calendar.AddYears(1))
            {
                // Begin sample processing of current year.

                // Move to first day of year. Change of month can affect day so order of assignments is important.
                calendar.Month(calendar.FirstMonthInThisYear());
                calendar.Day(calendar.FirstDayInThisMonth());

                // Set time to midnight (local).
                calendar.Period(calendar.FirstPeriodInThisDay());    // All days have 1 or 2 periods depending on clock type
                calendar.Hour(calendar.FirstHourInThisPeriod());     // Hours start from 12 or 0 depending on clock type
                calendar.Minute(0);
                calendar.Second(0);
                calendar.Nanosecond(0);

                if (calendar.Year() % 1000 == 0)
                {
                    results << L"\n";
                }
                else if (calendar.Year() % 10 == 0)
                {
                    results << L".";
                }

                // End sample processing of current year.

                // Break after processing last year.
                if (calendar.Year() == calendar.LastYearInThisEra())
                {
                    break;
                }
            }
            results << L"\n";

            // Break after processing last era.
            if (calendar.Era() == calendar.LastEra())
            {
                break;
            }
        }
        results << L"\n";

        // This section shows enumeration through the hours in a day to demonstrate that the number of time units in a given period (hours in a day, minutes in an hour, etc.)
        // should not be regarded as fixed. With Daylight Saving Time and other local calendar adjustments, a given day may have not have 24 hours, and
        // a given hour may not have 60 minutes, etc.
        results <<
            L"The number of hours in a day is not constant. " <<
            L"The US calendar transitions from daylight saving time to standard time on 4 November 2012:\n\n";

        // Create a DateTimeFormatter to display dates
        DateTimeFormatter displayDate(L"longdate");

        // Create a Gregorian calendar for the US with 12-hour clock format
        Calendar currentCal({ L"en-US" }, CalendarIdentifiers::Gregorian(), ClockIdentifiers::TwentyFourHour(), L"America/Los_Angeles");

        // Set the calendar to a the date of the Daylight Saving Time-to-Standard Time transition for the US in 2012.
        // An easier way to set the calendar date and time is to set the currentCal.Year, Month, etc. properties.
        // However, we calculate it the complicated way to demonstrate interoperability between Calendar and Windows::Foundation::DateTime.
        // DST ends in the America/Los_Angeles time zone at 4 November 2012 02:00 PDT = 4 November 2012 09:00 UTC.
        SYSTEMTIME dstSystemTime;
        dstSystemTime.wYear = 2012;
        dstSystemTime.wMonth = 11;
        dstSystemTime.wDay = 4;
        dstSystemTime.wHour = 9;
        dstSystemTime.wMinute = 0;
        dstSystemTime.wSecond = 0;
        dstSystemTime.wMilliseconds = 0;
        FILETIME dstFileTime;
        SystemTimeToFileTime(&dstSystemTime, &dstFileTime);
        DateTime dstDateTime = clock::from_file_time(dstFileTime);
        currentCal.SetDateTime(dstDateTime);

        // Set the current calendar to one day before DST change. Create a second calendar for comparision and set it to one day after DST change.
        Calendar endDate = currentCal.Clone();
        currentCal.AddDays(-1);
        endDate.AddDays(1);

        // Enumerate the day before, the day of, and the day after the 2012 DST-to-Standard time transition
        while (currentCal.Day() <= endDate.Day())
        {
            // Process current day.
            DateTime date = currentCal.GetDateTime();
            results << std::wstring_view(displayDate.Format(date)) << L" contains " << currentCal.NumberOfHoursInThisPeriod() << L" hour(s)\n";

            // Enumerate all hours in this day.
            // Create a calendar to represent the following day.
            Calendar nextDay = currentCal.Clone();
            nextDay.AddDays(1);
            for (currentCal.Hour(currentCal.FirstHourInThisPeriod()); true; currentCal.AddHours(1))
            {
                // Display the hour for each hour in the day.
                results << std::wstring_view(currentCal.HourAsPaddedString(2)) << L" ";

                // Break upon reaching the next period (i.e. the first period in the following day).
                if (currentCal.Day() == nextDay.Day() && currentCal.Period() == nextDay.Period())
                {
                    break;
                }
            }
            results << L"\n";
        }

        // Display results
        OutputTextBlock().Text(results.str());
    }
}


text:
package rawmdns

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"strings"
)

type DNSMessage struct {
	Hdr        DNSHeader
	Questions  []DNSQuestion
	Answers    []DNSResourceRecord // any XYZRecord from this package
	Additional []DNSResourceRecord // any XYZRecord from this package
	//NameServers []DNSNSRecord
}

func (dm DNSMessage) ToBytes() ([]byte, error) {
	ret, err := dm.Hdr.toBytes()
	if err != nil {
		return nil, fmt.Errorf("DNSHeader.ToBytes: %s", err)
	}

	for _, dq := range dm.Questions {
		qb, err := dq.toBytes()
		if err != nil {
			return nil, fmt.Errorf("DNSQuestion.ToBytes: %s", err)
		}
		ret = append(ret, qb...)
	}

	for _, answer := range dm.Answers {
		rrr, err := answer.toRawDNSResourceRecord()
		if err != nil {
			return nil, fmt.Errorf("DNSResourceRecord.torawDNSResourceRecord: %s", err)
		}
		ab, err := rrr.toBytes()
		ret = append(ret, ab...)
	}

	for _, addl := range dm.Additional {
		rrr, err := addl.toRawDNSResourceRecord()
		if err != nil {
			return nil, fmt.Errorf("DNSResourceRecord.torawDNSResourceRecord: %s", err)
		}
		ab, err := rrr.toBytes()
		ret = append(ret, ab...)
	}

	return ret, nil
}

type rawDNSHeader struct {
	Id      uint16
	Flag    [2]byte
	QdCount uint16
	AnCount uint16
	NSCount uint16
	ArCount uint16
}

func (rdh rawDNSHeader) toDNSHeader() DNSHeader {
	dh := DNSHeader{}
	dh.ID = rdh.Id
	dh.NumQuestions = rdh.QdCount
	dh.NumAnswers = rdh.AnCount
	dh.NumNameServers = rdh.NSCount
	dh.NumAddlRecords = rdh.ArCount

	if rdh.Flag[0]>>7 == 1 {
		dh.IsResponse = true
	}
	dh.OpCode = OpCode((rdh.Flag[0] >> 3) &^ 0x10)
	if (rdh.Flag[0]&0x4)>>2 == 1 {
		dh.Authoritative = true
	}
	if (rdh.Flag[0]&0x2)>>1 == 1 {
		dh.Truncated = true
	}
	if rdh.Flag[0]&0x1 == 1 {
		dh.RecursionDesired = true
	}
	if rdh.Flag[1]>>7 == 1 {
		dh.RecursionAvailable = true
	}
	dh.ResponseCode = ResponseCode(rdh.Flag[1] & 0xF)

	return dh
}

func (rdh rawDNSHeader) toBytes() ([]byte, error) {
	buf := bytes.Buffer{}
	err := binary.Write(&buf, binary.BigEndian, rdh)
	if err != nil {
		return nil, fmt.Errorf("binary.Write(): %s", err)
	}
	return buf.Bytes(), nil
}

type DNSHeader struct {
	ID                 uint16
	IsResponse         bool
	OpCode             OpCode
	Authoritative      bool
	Truncated          bool
	RecursionDesired   bool
	RecursionAvailable bool
	Reserved           bool
	AuthenticatedData  bool
	CheckingDisabled   bool
	// This actually contains two fields we should decode:
	// Authenticated Data (on response)
	// Checking Disabled (on query)
	// These are defined in RFC 2065 section 6.1
	// http://freesoft.org/CIE/RFC/2065/40.htm
	ResponseCode   ResponseCode
	NumQuestions   uint16
	NumAnswers     uint16
	NumNameServers uint16
	NumAddlRecords uint16
}

func (dh DNSHeader) toRaw() rawDNSHeader {
	var rdh rawDNSHeader
	rdh.Id = uint16(dh.ID)
	rdh.QdCount = uint16(dh.NumQuestions)
	rdh.AnCount = uint16(dh.NumAnswers)
	rdh.NSCount = uint16(dh.NumNameServers)
	rdh.ArCount = uint16(dh.NumAddlRecords)

	if dh.IsResponse {
		rdh.Flag[0] |= 0x80
	}
	rdh.Flag[0] |= uint8(dh.OpCode) << 3
	if dh.Authoritative {
		rdh.Flag[0] |= 0x4
	}
	if dh.Truncated {
		rdh.Flag[0] |= 0x2
	}
	if dh.RecursionDesired {
		rdh.Flag[0] |= 0x1
	}
	if dh.RecursionAvailable {
		rdh.Flag[1] |= 0x80
	}
	rdh.Flag[1] |= byte(dh.ResponseCode & 0xF)

	return rdh
}

func (dh DNSHeader) toBytes() ([]byte, error) {
	return dh.toRaw().toBytes()
}

type rawDNSQuestion struct {
	domainLabels rawLabels
	static       rawQuestionStatic
}

type rawQuestionStatic struct {
	Type  RecordType
	Class RecordClass
}

func (rq rawDNSQuestion) toBytes() ([]byte, error) {
	var buf bytes.Buffer
	terminusLabel := rawLabel{length: 0, content: ""}
	outLabels := append(rq.domainLabels, terminusLabel)
	for _, l := range outLabels {
		_, err := buf.Write(l.toBytes())
		if err != nil {
			return nil, fmt.Errorf("bytes.Buffer.Write: %s", err)
		}
	}

	err := binary.Write(&buf, binary.BigEndian, rq.static)
	if err != nil {
		return nil, fmt.Errorf("binary.Write: %s", err)
	}
	return buf.Bytes(), nil
}

func (rq rawDNSQuestion) toQuestion() DNSQuestion {
	q := DNSQuestion{}
	for _, s := range rq.domainLabels {
		if len(q.Domain) > 0 {
			q.Domain += "."
		}
		q.Domain += s.content
	}
	q.Type = rq.static.Type
	q.Class = rq.static.Class & 0x7FFF
	if rq.static.Class&0x8000 == 0x8000 {
		q.AcceptUnicastResponse = true
	}

	return q
}

type DNSQuestion struct {
	Domain                string
	Type                  RecordType
	Class                 RecordClass
	AcceptUnicastResponse bool
}

func (q DNSQuestion) toRaw() rawDNSQuestion {
	var rq rawDNSQuestion
	for _, s := range strings.Split(q.Domain, ".") {
		l := rawLabel{
			length:  uint8(len(s)),
			content: s,
		}
		rq.domainLabels = append(rq.domainLabels, l)
	}
	rq.static.Type = q.Type
	rq.static.Class = q.Class
	if q.AcceptUnicastResponse {
		rq.static.Class = rq.static.Class | 0x8000
	}
	return rq
}

func (q DNSQuestion) toBytes() ([]byte, error) {
	return q.toRaw().toBytes()
}


text:
<?php

class startSubscriberDataExchangeResponse
{
}


text:
<sitemesh>

  <mapping path='/_ah/*' exclude='true' />

  <mapping path="/sstday/*" exclude="true"/>

    <!--<mapping path='/*' decorator='/WEB-INF/layouts/main.gtpl' />-->
</sitemesh>


text:
#include <folly/Random.h>

#include <atomic>
#include <unistd.h>
#include <sys/time.h>
#include <mutex>
#include <random>
#include <array>

#include <glog/logging.h>
#include <folly/CallOnce.h>
#include <folly/File.h>
#include <folly/FileUtil.h>
#include <folly/ThreadLocal.h>

#ifdef _MSC_VER
# include <wincrypt.h>
#endif

namespace folly {

namespace {

void readRandomDevice(void* data, size_t size) {
#ifdef _MSC_VER
  static folly::once_flag flag;
  static HCRYPTPROV cryptoProv;
  folly::call_once(flag, [&] {
    PCHECK(CryptAcquireContext(&cryptoProv, nullptr, nullptr,
                               PROV_RSA_FULL, 0));
  });
  CHECK(size <= std::numeric_limits<DWORD>::max());
  PCHECK(CryptGenRandom(cryptoProv, (DWORD)size, (BYTE*)data));
#else
  // Keep the random device open for the duration of the program.
  static int randomFd = ::open("/dev/urandom", O_RDONLY);
  PCHECK(randomFd >= 0);
  auto bytesRead = readFull(randomFd, data, size);
  PCHECK(bytesRead >= 0 && size_t(bytesRead) == size);
#endif
}

class BufferedRandomDevice {
 public:
  static constexpr size_t kDefaultBufferSize = 128;

  explicit BufferedRandomDevice(size_t bufferSize = kDefaultBufferSize);

  void get(void* data, size_t size) {
    if (LIKELY(size <= remaining())) {
      memcpy(data, ptr_, size);
      ptr_ += size;
    } else {
      getSlow(static_cast<unsigned char*>(data), size);
    }
  }

 private:
  void getSlow(unsigned char* data, size_t size);

  inline size_t remaining() const {
    return buffer_.get() + bufferSize_ - ptr_;
  }

  const size_t bufferSize_;
  std::unique_ptr<unsigned char[]> buffer_;
  unsigned char* ptr_;
};

BufferedRandomDevice::BufferedRandomDevice(size_t bufferSize)
  : bufferSize_(bufferSize),
    buffer_(new unsigned char[bufferSize]),
    ptr_(buffer_.get() + bufferSize) {  // refill on first use
}

void BufferedRandomDevice::getSlow(unsigned char* data, size_t size) {
  DCHECK_GT(size, remaining());
  if (size >= bufferSize_) {
    // Just read directly.
    readRandomDevice(data, size);
    return;
  }

  size_t copied = remaining();
  memcpy(data, ptr_, copied);
  data += copied;
  size -= copied;

  // refill
  readRandomDevice(buffer_.get(), bufferSize_);
  ptr_ = buffer_.get();

  memcpy(data, ptr_, size);
  ptr_ += size;
}

}  // namespace

void Random::secureRandom(void* data, size_t size) {
  static ThreadLocal<BufferedRandomDevice> bufferedRandomDevice;
  bufferedRandomDevice->get(data, size);
}

class ThreadLocalPRNG::LocalInstancePRNG {
 public:
  LocalInstancePRNG() : rng(Random::create()) { }

  Random::DefaultGenerator rng;
};

ThreadLocalPRNG::ThreadLocalPRNG() {
  static folly::ThreadLocal<ThreadLocalPRNG::LocalInstancePRNG> localInstance;
  local_ = localInstance.get();
}

uint32_t ThreadLocalPRNG::getImpl(LocalInstancePRNG* local) {
  return local->rng();
}

}


text:
Do you need to assemble groups with an emphasis on group dynamics? Do the groups need to be unique based on a group history? Pairs aims to solve this problem by doing all the relational work for you. If you don't like your groups you can reroll or lock in particular pairs.

## License

MIT License

Copyright (c) 2016 Ryan Busby


text:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NoRebindableSyntax #-}
{-# LANGUAGE OverloadedStrings #-}

module Duckling.Time.EL.Rules
  ( rules
  ) where

import Data.HashMap.Strict (HashMap)
import Data.Text (Text)
import Prelude
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as Text

import Duckling.Dimensions.Types
import Duckling.Duration.Helpers (duration, isGrain)
import Duckling.Duration.Types (DurationData(DurationData))
import Duckling.Numeral.Helpers (parseInt, numeralMapEL)
import Duckling.Numeral.Types (NumeralData(..))
import Duckling.Ordinal.Types (OrdinalData(..), isBetween)
import Duckling.Regex.Types
import Duckling.Time.Helpers
import Duckling.Time.Types (TimeData(..))
import Duckling.Types
import qualified Duckling.Numeral.Types as TNumeral
import qualified Duckling.Ordinal.Types as TOrdinal
import qualified Duckling.Time.Types as TTime
import qualified Duckling.TimeGrain.Types as TG

ruleInstants :: [Rule]
ruleInstants = mkRuleInstants
  [ ( "now"             , TG.Second,  0, "(αμέσως\\s+)?τώρα(\\s+αμέσως)?|αυτή τη στιγμή" )
  , ( "today"           , TG.Day   ,  0, "σήμερα"                   )
  , ( "tomorrow"        , TG.Day   ,  1, "(επ)?αύριο"               )
  , ( "yesterday"       , TG.Day   , -1, "ε?χ[θτ][εέ]ς"             )
  , ( "after tomorrow"  , TG.Day   ,  2, "μεθαύριο"                 )
  , ( "before yesterday", TG.Day   , -2, "προχ[θτ]ές"               )
  , ( "EOD|End of day"  , TG.Day   ,  1, "τέλου?ς\\s+της\\s+η?μέρας")
  , ( "EOM|End of month", TG.Month ,  1, "τέλου?ς\\s+του\\s+μήνα"   )
  , ( "EOY|End of year" , TG.Year  ,  1, "τέλου?ς\\s+του\\s+χρόνου" )
  ]

daysOfWeek :: [(Text, String)]
daysOfWeek =
  [ ( "monday"    , "δευτ(έρας?|\\.?)"          )
  , ( "tuesday"   , "τρ[ιί](της?|\\.?)"         )
  , ( "wednesday" , "τετ(άρτης?|\\.?)"          )
  , ( "thursday"  , "π[εέ]μ(πτης?|\\.?)"        )
  , ( "friday"    , "παρ(ασκευής?|\\.?)"        )
  , ( "saturday"  , "σ[αά]β(β[αά]το[νυ]?|\\.?)" )
  , ( "sunday"    , "κυρ(ιακής?|\\.?)"          )
  ]

ruleDaysOfWeek :: [Rule]
ruleDaysOfWeek = zipWith go daysOfWeek [1..7]
  where
    go (name, regexPattern) i = Rule
      { name = name
      , pattern = [regex regexPattern]
      , prod = const . tt . mkOkForThisNext $ dayOfWeek i
      }

months :: [(Text, String)]
months =
  [ ( "January"  , "ιαν(ου[αά]ρ[ιί]ο[υς]?)?|γενάρης?"    )
  , ( "February" , "φεβ(ρου[αά]ρ[ιί]ο[υς]?)?|φλεβάρης?"  )
  , ( "March"    , "μ[αά]ρ(τ([ιί]ο([νυ]?)|η)ς?)?"        )
  , ( "April"    , "απρ([ιί]λ([ιί]ο([νυ]?)|η)ς?)?"       )
  , ( "May"      , "μ[αά]([ιίϊΐ]ο[νυ]?|η)ς?"             )
  , ( "June"     , "ιο[υύ]ν([ιί]ο[υν]?|η)?ς?"            )
  , ( "July"     , "ιο[υύ]λ([ιί]ο[υν]?|η)?ς?"            )
  , ( "August"   , "α[υύ]γ(ο[υύ]στο(ν|υ|ς)?)?"           )
  , ( "September", "σεπτ([εέ]μβρ([ιί]ο([νυ]?)|η)ς?)?"    )
  , ( "October"  , "οκτ([ωώ]βρ([ιί]ο([νυ]?)|η)ς?)?"      )
  , ( "November" , "νο[εέ](μ(βρ([ιί]ο([νυ]?)|η)ς?)?)?"   )
  , ( "December" , "δεκ([εέ]μβρ([ιί]ο([νυ]?)|η)ς?)?"     )
  ]

ruleMonths :: [Rule]
ruleMonths = zipWith go months [1..12]
  where
    go (name, regexPattern) i = Rule
      { name = name
      , pattern = [regex regexPattern]
      , prod = const . tt . mkOkForThisNext $ month i
      }

ruleSeasons :: [Rule]
ruleSeasons = mkRuleSeasons
  [ ( "summer" , "καλοκα[ιί]ρι(ού)?", monthDay  6 21, monthDay  9 23 )
  , ( "fall"   , "φθιν[οό]π[ωώ]ρου?", monthDay  9 23, monthDay 12 21 )
  , ( "winter" , "χειμώνας?"        , monthDay 12 21, monthDay  3 20 )
  , ( "spring" , "άνοιξης?"         , monthDay  3 20, monthDay  6 21 )
  ]

ruleHolidays :: [Rule]
ruleHolidays = map go holidays
  where
    go (name, td, regexPattern) = Rule
      { name = name
      , pattern = [regex regexPattern]
      , prod = const . tt $ mkOkForThisNext td
      }

holidays :: [(Text, TimeData, String)]
holidays =
  [ ("new year's day"   , monthDay 1 1, "πρωτοχρονιάς?")
  , ("valentine's day"  , monthDay 2 14, "αγίου\\s+βαλεντίνου")
  , ("halloween day"    , monthDay 10 31, "halloween")
  , ("Epiphany"         , monthDay 1 6, "θεοφ(αά)νε[ιί](α|ων)|φ[ωώ]τ(α|ων)")
  , ("annunciation day" , monthDay 3 25, "ευαγγελισμ(ός|ού)\\s+της\\s+θεοτόκου")
  , ("revolution day"   , monthDay 3 25
                        , "η?μέρα\\s+(της\\s+)?(ελληνικής\\s+)?επανάστασης")
  , ("assumption day"   , monthDay  8 15
                        , "κο[ιί]μ[ηή]σ(η|ις|εως)\\s+της\\s+θεοτόκου")
  , ("christmas eve"    , monthDay 12 24, "παραμν(ή|έ)ς?\\s+χριστουγέννων")
  , ("christmas"        , monthDay 12 25, "χριστο[υύ]γ[εέ]νν(α|ων)")
  , ("new year's eve"   , monthDay 12 31, "παραμον(ή|έ)ς?\\s+πρωτοχρονιάς")
  , ("Mother's Day"     , nthDOWOfMonth 2 7 5, "η?μέρας?\\s+της\\s+μητέρας")
  , ("Father's Day"     , nthDOWOfMonth 3 7 6
                        , "(γιορτής?|η?μέρας?)\\s+του\\s+πατέρα")
  ]

ruleRelativeIntegerToOrAfterIntegerPartOfDay :: Rule
ruleRelativeIntegerToOrAfterIntegerPartOfDay = Rule
  { name = "relative integer (minutes) to|till|before|after <integer> (time-of-day)"
  , pattern =
    [ Predicate $ isIntegerBetween 1 30
    , regex "(πριν|μετά)"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (Token Numeral NumeralData{TNumeral.value = v}:
       Token RegexMatch (GroupMatch (match:_)):
       Token Time td:
       _) -> case Text.toLower match of
        "πριν" -> tt $ durationBefore (duration TG.Minute $ floor v) td
        _      -> tt $ durationAfter (duration TG.Minute $ floor v) td
      _ -> Nothing
  }

ruleQuarterBeforeOrAfterIntegerHourofday :: Rule
ruleQuarterBeforeOrAfterIntegerHourofday = Rule
  { name = "quarter to|past <integer> (hour-of-day)"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "(παρά|και)\\s+τέταρτο"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:
       Token RegexMatch (GroupMatch (match:_)):
       _) -> case Text.toLower match of
        "παρά" -> Token Time <$> minutesBefore 15 td
        _      -> Token Time <$> minutesAfter  15 td
      _ -> Nothing
  }

ruleHalfAfterIntegerHourofday :: Rule
ruleHalfAfterIntegerHourofday = Rule
  { name = "half after|past <integer> (hour-of-day)"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "και μισή"
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _) -> tt $ hourMinute is12H hours 30
      _ -> Nothing
  }

ruleHalfAfterIntegerHourofday2 :: Rule
ruleHalfAfterIntegerHourofday2 = Rule
  { name = "<integer>-and-half (hour-of-day)"
  , pattern =
    [ regex $ "(μιά|ενά|δυό|τρεισή|τεσσερι?σή|πεντέ|εξί|ε[πφ]τά|ο[κχ]τώ|εννιά|"
           ++ "δεκά|εντεκά|δωδεκά)μισ[ιη]ς?"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (num:_)):_) ->
        case HashMap.lookup (Text.toLower num) numeralMapEL of
          Just hours -> tt $ hourMinute True hours 30
          _ -> Nothing
      _ -> Nothing
  }

ruleOrdinalCycleOfTime :: Rule
ruleOrdinalCycleOfTime = Rule
  { name = "<ordinal> <cycle> of <time>"
  , pattern =
    [ dimension Ordinal
    , dimension TimeGrain
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Ordinal od:Token TimeGrain grain:Token Time td:_) ->
        tt $ cycleNthAfter True grain (TOrdinal.value od - 1) td
      _ -> Nothing
  }

ruleLastTime :: Rule
ruleLastTime = Rule
  { name = "last <time>"
  , pattern =
    [ regex "(τελευταί|περασμέν|προηγο[υύ]μ[εέ]ν)(α|ά|ο[υύ]?|η|ή|ε|έ|ω|ώ)ν?ς?"
    , Predicate isOkWithThisNext
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ predNth (-1) False td
      _ -> Nothing
  }

ruleDatetimeDatetimeInterval :: Rule
ruleDatetimeDatetimeInterval = Rule
  { name = "<datetime> - <datetime> (interval)"
  , pattern =
    [ Predicate isNotLatent
    , regex "\\-|μ[εέ](χρι)?(\\s+τις)?"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time . notLatent <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleEvening :: Rule
ruleEvening = Rule
  { name = "evening"
  , pattern =
    [ regex "βράδυ"
    ]
  , prod = \_ ->
      let from = hour False 18
          to = hour False 0
      in Token Time . mkLatent . partOfDay <$>
           interval TTime.Open from to
  }

ruleTheDayofmonthNonOrdinal :: Rule
ruleTheDayofmonthNonOrdinal = Rule
  { name = "the <day-of-month> (non ordinal)"
  , pattern =
    [ regex "τ?η[νς]?"
    , Predicate $ isIntegerBetween 1 31
    ]
  , prod = \tokens -> case tokens of
      (_:token:_) -> Token Time . dayOfMonth <$> getIntValue token
      _ -> Nothing
  }

rulePartOfMonth :: Rule
rulePartOfMonth = Rule
  { name = "part of <named-month>"
  , pattern =
    [ regex "(αρχ(?:ές|η)|μέσ[οα]υ?|τέλ(?:ου?ς|η))(?:\\s+του)?"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):Token Time td:_) -> do
        (sd, ed) <- case Text.take 3 $ Text.toLower match of
          "αρχ" -> Just (1, 10)
          "μέσ" -> Just (11, 20)
          "τέλ" -> Just (21, -1)
          _     -> Nothing
        start <- intersect td $ dayOfMonth sd
        end <- if ed /= -1
          then intersect td $ dayOfMonth ed
          else Just $ cycleLastOf TG.Day td
        Token Time <$> interval TTime.Open start end
      _ -> Nothing
  }

ruleInDuration :: Rule
ruleInDuration = Rule
  { name = "in <duration>"
  , pattern =
    [ regex "σε"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) -> tt $ inDuration dd
      _ -> Nothing
  }

ruleLastCycleOfTime :: Rule
ruleLastCycleOfTime = Rule
  { name = "last <cycle> of <time>"
  , pattern =
    [ regex "τελευταί(ο[ιυ]?ς?|α|ες|ων)"
    , dimension TimeGrain
    , regex "σ?τ(ο[υν]?|η[νς]?|ων)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleLastOf grain td
      _ -> Nothing
  }

ruleLastCycleOfTimeS :: Rule
ruleLastCycleOfTimeS = Rule
  { name = "last <cycle> <time>'s'"
  , pattern =
    [ regex "τελευταί(ο[ιυ]?ς?|α|ες|ων)"
    , dimension TimeGrain
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:Token Time td:_) ->
        tt $ cycleLastOf grain td
      _ -> Nothing
  }

ruleFromDatetimeDatetimeInterval :: Rule
ruleFromDatetimeDatetimeInterval = Rule
  { name = "from <datetime> - <datetime> (interval)"
  , pattern =
    [ regex "από(\\s+τ(ις|η))?"
    , Predicate $ and . sequence [isNotLatent, isATimeOfDay]
    , regex "\\-|μέχρι(\\s+τ(ις|η))?"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

-- Specific for time-of-day, to help resolve ambiguities
ruleIntervalTODDash :: Rule
ruleIntervalTODDash = Rule
  { name = "<time-of-day> - <time-of-day> (interval)"
  , pattern =
    [ Predicate $ and . sequence [isNotLatent, isATimeOfDay]
    , regex "\\-|μέχρι"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleMonthDdddInterval :: Rule
ruleMonthDdddInterval = Rule
  { name = "dd-dd <month> (interval)"
  , pattern =
    [ regex "(από\\s+)?(τ[ιη][νς]?\\s+)?([012]?\\d|30|31)η?ς?"
    , regex "\\-|μ[εέ](χρι)?(?:\\s+τ[ιη][νς]?)?"
    , regex "([012]?\\d|30|31)η?ς?"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (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
  }

ruleTheCycleAfterTime :: Rule
ruleTheCycleAfterTime = Rule
  { name = "the <cycle> after <time>"
  , pattern =
    [ dimension TimeGrain
    , regex "μετά τ(ου?|η|ι|α|ου)ν?ς?"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter False grain 1 td
      _ -> Nothing
  }

ruleTheCycleOfTime :: Rule
ruleTheCycleOfTime = Rule
  { name = "the <cycle> of <time>"
  , pattern =
    [ dimension TimeGrain
    , regex "τ(ου|ης)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter True grain 0 td
      _ -> Nothing
  }

ruleTheCycleBeforeTime :: Rule
ruleTheCycleBeforeTime = Rule
  { name = "the <cycle> before <time>"
  , pattern =
    [ dimension TimeGrain
    , regex "πριν τ(ον?|ην?|α|ους)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter False grain (-1) td
      _ -> Nothing
  }

ruleYearLatent2 :: Rule
ruleYearLatent2 = Rule
  { name = "year (latent)"
  , pattern =
    [ Predicate $ isIntegerBetween 2101 10000
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        v <- getIntValue token
        tt . mkLatent $ year v
      _ -> Nothing
  }

ruleTimeAfterNext :: Rule
ruleTimeAfterNext = Rule
  { name = "<time> after next"
  , pattern =
    [ regex "μεθεπ[οό]μ[εέ]ν(ο[ιυ]?ς?|ης?|ων)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ predNth 2 True td
      _ -> Nothing
  }

ruleThisDayofWeek :: Rule
ruleThisDayofWeek = Rule
  { name = "this <day-of-week>"
  , pattern =
    [ regex "αυτή[νς]? τη[νς]?"
    , Predicate isADayOfWeek
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ predNth 0 True td
      _ -> Nothing
  }

ruleTheDayOf :: Rule
ruleTheDayOf = Rule
  { name = "on the day of <day>"
  , pattern =
    [ regex "ανήμερα"
    , Predicate $ isGrainOfTime TG.Day
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ predNth 0 True td
      _ -> Nothing
  }

ruleThisDayofWeek2 :: Rule
ruleThisDayofWeek2 = Rule
  { name = "(this) coming <day-of-week>"
  , pattern =
    [ regex "ερχ[οό]μ[εέ]νη[ςν]?"
    , Predicate isADayOfWeek
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ predNth 0 True td
      _ -> Nothing
  }

ruleBetweenTimeofdayAndTimeofdayInterval :: Rule
ruleBetweenTimeofdayAndTimeofdayInterval = Rule
  { name = "between <time-of-day> and <time-of-day> (interval)"
  , pattern =
    [ regex "μεταξύ|ανάμεσα"
    , Predicate isATimeOfDay
    , regex "(και(\\s+τ(ου|ης))?|\\-)"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleNextCycle :: Rule
ruleNextCycle = Rule
  { name = "next <cycle>"
  , pattern =
    [ regex "ε(π|ρχ)[οό]μ[εέ]ν(ο[ιυ]?ς?|ης?|ες|ων)"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_) -> tt $ cycleNth grain 1
      _ -> Nothing
  }

ruleTimeofdayApproximately :: Rule
ruleTimeofdayApproximately = Rule
  { name = "<time-of-day> approximately"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "περίπου|και κάτι"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleInDurationFromTime :: Rule
ruleInDurationFromTime = Rule
  { name = "in <duration> from <time>"
  , pattern =
    [ regex "σε"
    , dimension Duration
    , regex "(ξεκινώντας\\s+)?από"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_:Token Time td1:_) ->
        tt $ durationAfter dd td1
      _ -> Nothing
}

ruleDurationFromNow :: Rule
ruleDurationFromNow = Rule
  { name = "<duration> from now"
  , pattern =
    [ dimension Duration
    , regex "από τώρα"
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:_) -> tt $ inDuration dd
      _ -> Nothing
  }

ruleLunch :: Rule
ruleLunch = Rule
  { name = "lunch"
  , pattern =
    [ regex "μεσημεριαν(ό|ού)( γεύμα(τος)?)?"
    ]
  , prod = \_ ->
      let from = hour False 12
          to = hour False 14
      in Token Time . mkLatent . partOfDay <$>
           interval TTime.Open from to
  }

ruleLastCycle :: Rule
ruleLastCycle = Rule
  { name = "last <cycle>"
  , pattern =
    [ regex "τελευταί(ου?|ας?)"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_) -> tt . cycleNth grain $ - 1
      _ -> Nothing
  }

ruleAfternoon :: Rule
ruleAfternoon = Rule
  { name = "afternoon"
  , pattern =
    [ regex "απ[οό]γε[υύ]μα(τος)?"
    ]
  , prod = \_ ->
      let from = hour False 12
          to = hour False 18
      in Token Time . mkLatent . partOfDay <$>
           interval TTime.Open from to
  }

ruleDayofmonthOrdinalNamedmonth :: Rule
ruleDayofmonthOrdinalNamedmonth = Rule
  { name = "<day-of-month> (ordinal or number) <named-month>"
  , pattern =
    [ Predicate isDOMValue
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (day:Token Time month:_) -> Token Time <$> intersectDOM month day
      _ -> Nothing
  }

ruleNamedmonthDayofmonth :: Rule
ruleNamedmonthDayofmonth = Rule
  { name = "<named-month> <day-of-month> (ordinal or number)"
  , pattern =
    [ Predicate isAMonth
    , Predicate isDOMValue
    ]
  , prod = \tokens -> case tokens of
      (Token Time month:day:_) -> Token Time <$> intersectDOM month day
      _ -> Nothing
  }

ruleInduringThePartofday :: Rule
ruleInduringThePartofday = Rule
  { name = "in|during the <part-of-day>"
  , pattern =
    [ regex "κατά τη διάρκεια του|(μέσα )?σ?το"
    , Predicate isAPartOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleHourofdayIntegerAsRelativeMinutes :: Rule
ruleHourofdayIntegerAsRelativeMinutes = Rule
  { name = "<hour-of-day> <integer> (as relative minutes)"
  , pattern =
    [ Predicate $ and . sequence [isNotLatent, isAnHourOfDay]
    , regex "και"
    , Predicate $ isIntegerBetween 1 59
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData
       {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_:
       token:
       _) -> do
        n <- getIntValue token
        tt $ hourMinute is12H hours n
      _ -> Nothing
  }

ruleNthTimeAfterTime :: Rule
ruleNthTimeAfterTime = Rule
  { name = "nth <time> after <time>"
  , pattern =
    [ dimension Ordinal
    , Predicate $ or . sequence
        [ isADayOfWeek
        , isAMonth
        ]
    , regex "μετά"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Ordinal OrdinalData{TOrdinal.value = v}:
       Token Time td1:
       _:
       Token Time td2:
       _) -> tt $ predNthAfter (v - 1) td1 td2
      _ -> Nothing
  }

ruleMmdd :: Rule
ruleMmdd = Rule
  { name = "dd/mm"
  , pattern =
    [ regex "(3[01]|[12]\\d|0?[1-9])\\s?[/.-]\\s?(1[0-2]|0?[1-9])"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do
        d <- parseInt m1
        m <- parseInt m2
        tt $ monthDay m d
      _ -> Nothing
  }

ruleAfterDuration :: Rule
ruleAfterDuration = Rule
  { name = "after <duration>"
  , pattern =
    [ regex "μετά\\s+από"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) ->
        tt . withDirection TTime.After $ inDuration dd
      _ -> Nothing
  }

ruleTimeofdayLatent :: Rule
ruleTimeofdayLatent = Rule
  { name = "time-of-day (latent)"
  , pattern =
    [ Predicate $ isIntegerBetween 0 23
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        n <- getIntValue token
        tt . mkLatent $ hour (n < 12) n
      _ -> Nothing
  }

ruleExactlyTimeofday :: Rule
ruleExactlyTimeofday = Rule
  { name = "exactly <time-of-day>"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "ακριβώς"
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleBetweenDatetimeAndDatetimeInterval :: Rule
ruleBetweenDatetimeAndDatetimeInterval = Rule
  { name = "between <datetime> and <datetime> (interval)"
  , pattern =
    [ regex "μεταξύ|ανάμεσα"
    , Predicate isNotLatent
    , regex "(και|\\-)"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleDurationHenceAgo :: Rule
ruleDurationHenceAgo = Rule
  { name = "<duration> hence|ago"
  , pattern =
    [ dimension Duration
    , regex "(πριν|μετά)"
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:
       Token RegexMatch (GroupMatch (match:_)):
       _) -> case Text.toLower match of
        "πριν" -> tt $ durationAgo dd
        _ -> tt $ inDuration dd
      _ -> Nothing
  }

ruleHenceAgoDuration :: Rule
ruleHenceAgoDuration = Rule
  { name = "before <duration>"
  , pattern =
    [ regex "(πριν(\\s+από)?|εδώ και)"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):
       Token Duration dd:
       _) -> case Text.toLower match of
        "εδώ και" -> tt $ inDuration dd
        _ -> tt $ durationAgo dd
      _ -> Nothing
  }

ruleIntervalUntilTOD :: Rule
ruleIntervalUntilTOD = Rule
  { name = "until <time-of-day>"
  , pattern =
    [ regex "πριν"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ withDirection TTime.Before td
      _ -> Nothing
  }

ruleByTheEndOfTime :: Rule
ruleByTheEndOfTime = Rule
  { name = "by the end of <time>"
  , pattern =
    [ regex "μέχρι το (τέλος|πέρας)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> Token Time <$> interval TTime.Closed td now
      _ -> Nothing
  }

ruleAfterWork :: Rule
ruleAfterWork = Rule
  { name = "after work"
  , pattern =
    [ regex "μετά τη δουλειά"
    ]
  , prod = \_ -> do
      td2 <- interval TTime.Open (hour False 17) (hour False 21)
      Token Time . partOfDay <$> intersect today td2
  }

ruleLastNCycle :: Rule
ruleLastNCycle = Rule
  { name = "last n <cycle>"
  , pattern =
    [ regex "(τελευταί|περασμέν)(ο[ιυ]?ς?|[εα]ς?|ων)"
    , Predicate $ isIntegerBetween 1 9999
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:token:Token TimeGrain grain:_) -> do
        n <- getIntValue token
        tt $ cycleN True grain (- n)
      _ -> Nothing
  }

ruleWithinDuration :: Rule
ruleWithinDuration = Rule
  { name = "within <duration>"
  , pattern =
    [ regex "μέσα(\\s+σε)?"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) -> Token Time <$>
        interval TTime.Open now (inDuration dd)
      _ -> Nothing
  }

ruleMidnight :: Rule
ruleMidnight = Rule
  { name = "midnight"
  , pattern =
      [ regex "μεσάνυχτα"
      ]
  , prod = const $ tt $ hour False 0
  }

ruleNoon :: Rule
ruleNoon = Rule
  { name = "noon"
  , pattern =
      [ regex "μεσημ[εέ]ρι(ού)?"
      ]
  , prod = const $ tt $ hour False 12
  }

ruleDayofmonthNonOrdinalNamedmonth :: Rule
ruleDayofmonthNonOrdinalNamedmonth = Rule
  { name = "<day-of-month> (non-ordinal) <named-month>"
  , pattern =
    [ Predicate isDOMInteger
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:token:_) -> Token Time <$> intersectDOM td token
      _ -> Nothing
  }

rulePrecisionTimeofday :: Rule
rulePrecisionTimeofday = Rule
  { name = "about <time-of-day>"
  , pattern =
    [ regex "περίπου|ακριβώς"
    , Predicate $ isGrainFinerThan TG.Year
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleIntervalBy :: Rule
ruleIntervalBy = Rule
  { name = "until <time>"
  , pattern =
    [ regex "μέχρι"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> Token Time <$> interval TTime.Open now td
      _ -> Nothing
  }

ruleIntervalByTheEndOf :: Rule
ruleIntervalByTheEndOf = Rule
  { name = "by the end of <time>"
  , pattern =
    [ regex "μέχρι το τέλος"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> Token Time <$> interval TTime.Closed now td
      _ -> Nothing
  }

ruleUntilTimeofdayPostfix :: Rule
ruleUntilTimeofdayPostfix = Rule
  { name = "<time-of-day> until"
  , pattern =
    [ dimension Time
    , regex "το αργότερο"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) -> tt $ withDirection TTime.Before td
      _ -> Nothing
  }

ruleAtTimeofday :: Rule
ruleAtTimeofday = Rule
  { name = "at <time-of-day>"
  , pattern =
    [ regex "στις|@"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleNthTimeOfTime :: Rule
ruleNthTimeOfTime = Rule
  { name = "nth <time> of <time>"
  , pattern =
    [ dimension Ordinal
    , Predicate isNotLatent
    , regex "τ(ου|ης|ων)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Ordinal OrdinalData{TOrdinal.value = v}:
       Token Time td1:
       _:
       Token Time td2:
       _) -> Token Time . predNth (v - 1) False <$> intersect td2 td1
      _ -> Nothing
  }

ruleTimePartofday :: Rule
ruleTimePartofday = Rule
  { name = "<time> <part-of-day>"
  , pattern =
    [ dimension Time
    , Predicate isAPartOfDay
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleWeekend :: Rule
ruleWeekend = Rule
  { name = "week-end"
  , pattern =
    [ regex "σαββατοκύριακ(ου?|α|ων)|σκ"
    ]
  , prod = const . tt . mkOkForThisNext $ weekend
  }

ruleLastWeekendOfMonth :: Rule
ruleLastWeekendOfMonth = Rule
  { name = "last weekend of <named-month>"
  , pattern =
    [ regex "τελευταίου?\\s+(σαββατοκύριακου?|σκ)\\s+"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td2:_) -> tt $ predLastOf weekend td2
      _ -> Nothing
  }

ruleNextDayofweek :: Rule
ruleNextDayofweek = Rule
  { name = "next <day-of-week>"
  , pattern =
    [ regex "επ[οό]μ[εέ]ν(ο[ιυ]?ς?|ης?|ες|ων)"
    , Predicate isADayOfWeek
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ predNth 1 False td
      _ -> Nothing
  }

ruleNextTime :: Rule
ruleNextTime = Rule
  { name = "next <time>"
  , pattern =
    [ regex "επ[οό]μ[εέ]ν(ο[ιυ]?ς?|ης?|ες|ων)"
    , Predicate isOkWithThisNext
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ predNth 1 False td
      _ -> Nothing
  }

ruleOrdinalQuarterYear :: Rule
ruleOrdinalQuarterYear = Rule
  { name = "<ordinal> quarter <year>"
  , pattern =
    [ dimension Ordinal
    , Predicate $ isGrain TG.Quarter
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Ordinal od:_:Token Time td:_) ->
        tt $ cycleNthAfter False TG.Quarter (TOrdinal.value od - 1) td
      _ -> Nothing
  }

ruleYyyymmdd :: Rule
ruleYyyymmdd = Rule
  { name = "yyyy-mm-dd"
  , pattern =
    [ regex "(\\d{2,4})[.-](1[0-2]|0?[1-9])[.-](3[01]|[12]\\d|0?[1-9])"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
        y <- parseInt m1
        m <- parseInt m2
        d <- parseInt m3
        tt $ yearMonthDay y m d
      _ -> Nothing
  }

ruleOrdinalCycleAfterTime :: Rule
ruleOrdinalCycleAfterTime = Rule
  { name = "<ordinal> <cycle> after <time>"
  , pattern =
    [ dimension Ordinal
    , dimension TimeGrain
    , regex "μετά"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Ordinal od:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter True grain (TOrdinal.value od - 1) td
      _ -> Nothing
  }

ruleIntersect :: Rule
ruleIntersect = Rule
  { name = "intersect"
  , pattern =
    [ Predicate isNotLatent
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleIntersectBy :: Rule
ruleIntersectBy = Rule
  { name = "intersect by ','"
  , pattern =
    [ Predicate isNotLatent
    , regex ","
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleIntersectByOfFromS :: Rule
ruleIntersectByOfFromS = Rule
  { name = "intersect by 'of', 'from', 's"
  , pattern =
    [ Predicate isNotLatent
    , regex "τ(ου|ης)"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleNextNCycle :: Rule
ruleNextNCycle = Rule
  { name = "next n <cycle>"
  , pattern =
    [ regex "επ[οό]μ[εέ]ν(ο[ιυ]?ς?|ης?|ες|ων|α)"
    , Predicate $ isIntegerBetween 1 9999
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:token:Token TimeGrain grain:_) -> do
        v <- getIntValue token
        tt $ cycleN True grain v
      _ -> Nothing
  }

ruleADuration :: Rule
ruleADuration = Rule
  { name = "a <duration>"
  , pattern =
    [ regex "[εέ]ν(ας?|ός|ν)|μίας?"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) -> tt $ inDuration dd
      _ -> Nothing
  }

ruleMorning :: Rule
ruleMorning = Rule
  { name = "morning"
  , pattern =
    [ regex "(το\\s+)?πρωί"
    ]
  , prod = \_ ->
      let from = hour False 4
          to = hour False 12
      in Token Time . mkLatent . partOfDay <$>
           interval TTime.Open from to
  }

ruleEarlyMorning :: Rule
ruleEarlyMorning = Rule
  { name = "early morning"
  , pattern =
    [ regex "νωρίς\\s+(το\\s+)πρωί"
    ]
  , prod = \_ -> Token Time . partOfDay . mkLatent <$>
      interval TTime.Open (hour False 4) (hour False 9)
  }

ruleThisPartofday :: Rule
ruleThisPartofday = Rule
  { name = "this <part-of-day>"
  , pattern =
    [ regex "αυτ([οό]ύ?|ή[νς]?) τ(ον?|η[νς]?)"
    , Predicate isAPartOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> Token Time . partOfDay <$> intersect today td
      _ -> Nothing
  }

ruleThisCycle :: Rule
ruleThisCycle = Rule
  { name = "this <cycle>"
  , pattern =
    [ regex "αυτ([οό][νύ]?|ή[νς]?)\\s+τ(ον?|η[νς]?)"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_) -> tt $ cycleNth grain 0
      _ -> Nothing
  }

ruleDayofmonthNonOrdinalOfNamedmonth :: Rule
ruleDayofmonthNonOrdinalOfNamedmonth = Rule
  { name = "<day-of-month> (ordinal or number) of <named-month>"
  , pattern =
    [ Predicate isDOMValue
    , regex "του"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (day:_:Token Time td:_) -> Token Time <$> intersectDOM td day
      _ -> Nothing
  }

ruleYearLatent :: Rule
ruleYearLatent = Rule
  { name = "year (latent)"
  , pattern =
    [ Predicate $ isIntegerBetween 25 999
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        y <- getIntValue token
        tt . mkLatent $ year y
      _ -> Nothing
  }

ruleAfterTimeofday :: Rule
ruleAfterTimeofday = Rule
  { name = "after <time-of-day>"
  , pattern =
    [ regex "μετά"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ withDirection TTime.After td
      _ -> Nothing
  }

ruleCycleThis :: Rule
ruleCycleThis = Rule
  { name = "this <cycle>"
  , pattern =
    [ regex $ "αυτ([οό][υύ]?|[ηή]|[εέ]|ώ|ά)ν?ς?|"
           ++ "τρ[εέ]χ(ουσ)?(α|ε|ο|ω|ώ)ν?ς?"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ predNth 0 False td
      _ -> Nothing
  }

cyclesMap :: HashMap Text Int
cyclesMap = HashMap.fromList
  [ ("τρεχ"      , 0)
  , ("τρέχ"      , 0)
  , ("ερχόμεν"   , 0)
  , ("ερχομέν"   , 0)
  , ("επόμεν"    , 1)
  , ("επομέν"    , 1)
  , ("περασμέν"  , -1)
  , ("προηγούμεν", -1)
  , ("προηγουμέν", -1)
  ]

ruleCycleCurrentLastNext :: Rule
ruleCycleCurrentLastNext = Rule
  { name = "this|last|next <cycle>"
  , pattern =
    [ regex $ "(τρ[εέ]χ|επ[οό]μ[εέ]ν|ερχ[οό]μ[εέ]ν|περασμέν|προηγο[υύ]μ[εέ]ν)"
           ++ "(ουσ)?(α|ά|ο[υύ]?|η|ή|ε|έ|ω|ώ)ν?ς?"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (match:_)):Token TimeGrain grain:_) ->
        HashMap.lookup (Text.toLower match) cyclesMap >>= tt . cycleNth grain
      _ -> Nothing
  }

ruleNight :: Rule
ruleNight = Rule
  { name = "night"
  , pattern =
    [ regex "νύχτα"
    ]
  , prod = const $
      let from = hour False 20
          to = hour False 8
      in Token Time . mkLatent . partOfDay <$>
           interval TTime.Open from to
  }

ruleDayofmonthOrdinal :: Rule
ruleDayofmonthOrdinal = Rule
  { name = "<day-of-month> (ordinal)"
  , pattern =
    [ Predicate isDOMOrdinal
    ]
  , prod = \tokens -> case tokens of
      (Token Ordinal OrdinalData{TOrdinal.value = v}:_) ->
        tt . mkLatent $ dayOfMonth v
      _ -> Nothing
  }

ruleTimeofdayAmpm :: Rule
ruleTimeofdayAmpm = Rule
  { name = "<time-of-day> am|pm"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "([πμ])\\.?(μ\\.?)?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:Token RegexMatch (GroupMatch (ap:_)):_) ->
        tt $ timeOfDayAMPM (Text.toLower ap == "π") td
      _ -> Nothing
  }

ruleTimeofdayAmpmVerbose :: Rule
ruleTimeofdayAmpmVerbose = Rule
  { name = "<time-of-day> am|pm (verbose)"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "το\\s+(πρωί|απόγευμα)"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:Token RegexMatch (GroupMatch (ap:_)):_) ->
        tt $ timeOfDayAMPM (Text.toLower ap == "πρωί") td
      _ -> Nothing
  }

ruleAfterNextTime :: Rule
ruleAfterNextTime = Rule
  { name = "after next <time>"
  , pattern =
    [ regex "μετά τ(ο|η)ν? επόμεν(ο|η)ν?"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ predNth 1 True td
      _ -> Nothing
  }

ruleHhmm :: Rule
ruleHhmm = Rule
  { name = "hh:mm"
  , pattern =
    [ regex "((?:[01]?\\d)|(?:2[0-3]))[:ω]([0-5]\\d)ω?"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do
        h <- parseInt m1
        m <- parseInt m2
        tt $ hourMinute True h m
      _ -> Nothing
  }

ruleHHMMSS :: Rule
ruleHHMMSS = Rule
  { name = "hh:mm:ss"
  , pattern =
    [ regex "((?:[01]?\\d)|(?:2[0-3]))[:.]([0-5]\\d)[:.]([0-5]\\d)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (hh:mm:ss:_)):_) -> do
        h <- parseInt hh
        m <- parseInt mm
        s <- parseInt ss
        tt $ hourMinuteSecond True h m s
      _ -> Nothing
  }

-- We can't take generic TOD (e.g. "6:30am - 9pm").
-- Those are handled by other rules.
ruleIntervalTODAMPM :: Rule
ruleIntervalTODAMPM = Rule
 { name = "hh(:mm) - <time-of-day> am|pm"
 , pattern =
   [ regex "(?:από )?((?:[01]?\\d)|(?:2[0-3]))([:.]([0-5]\\d))?"
   , regex "\\-|:|μέχρι"
   , Predicate isATimeOfDay
   , regex "([πμ])(\\s|\\.)?(μ\\.?)?"
   ]
 , prod = \tokens -> case tokens of
     (Token RegexMatch (GroupMatch (hh:_:mm:_)):
      _:
      Token Time td2:
      Token RegexMatch (GroupMatch (ap:_)):
      _) -> do
       h <- parseInt hh
       let ampm = Text.toLower ap == "π"
           td1 = maybe (hour True h) (hourMinute True h) (parseInt mm)
       Token Time <$>
         interval TTime.Closed (timeOfDayAMPM ampm td1) (timeOfDayAMPM ampm td2)
     _ -> Nothing
 }

-- We can't take generic TOD (e.g. "6:30am - 9pm").
-- Those are handled by other rules.
ruleIntervalTODAMPMverbose :: Rule
ruleIntervalTODAMPMverbose = Rule
 { name = "hh(:mm) - <time-of-day> am|pm (verbose)"
 , pattern =
   [ regex "(?:από\\s+)?((?:[01]?\\d)|(?:2[0-3]))([:.]([0-5]\\d))?"
   , regex "\\-|:|μέχρι"
   , Predicate isATimeOfDay
   , regex "(?:το\\s+)?(πρωί|απόγευμα)"
   ]
 , prod = \tokens -> case tokens of
     (Token RegexMatch (GroupMatch (hh:_:mm:_)):
      _:
      Token Time td2:
      Token RegexMatch (GroupMatch (ap:_)):
      _) -> do
       h <- parseInt hh
       let ampm = Text.toLower ap == "πρωί"
           td1 = maybe (hour True h) (hourMinute True h) (parseInt mm)
       Token Time <$>
         interval TTime.Closed (timeOfDayAMPM ampm td1) (timeOfDayAMPM ampm td2)
     _ -> Nothing
 }

ruleTonight :: Rule
ruleTonight = Rule
  { name = "tonight"
  , pattern =
    [ regex "απόψε"
    ]
  , prod = \_ -> do
      td2 <- interval TTime.Open (hour False 18) (hour False 0)
      Token Time . partOfDay <$> intersect today td2
  }

ruleTomorrowNight :: Rule
ruleTomorrowNight = Rule
  { name = "tomorrownight"
  , pattern =
    [ regex "αύριο\\s+(το\\s+)?βράδυ"
    ]
  , prod = \_ -> do
      let td1 = cycleNth TG.Day 1
      td2 <- interval TTime.Open (hour False 18) (hour False 0)
      Token Time . partOfDay <$> intersect td1 td2
  }

ruleLastNight :: Rule
ruleLastNight = Rule
  { name = "lastnight"
  , pattern =
    [ regex "ε?χ[θτ][εέ]ς\\s+(το\\s+)?βράδυ"
    ]
  , prod = \_ -> do
      let td1 = cycleNth TG.Day $ - 1
      td2 <- interval TTime.Open (hour False 18) (hour False 0)
      Token Time . partOfDay <$> intersect td1 td2
  }

ruleYear :: Rule
ruleYear = Rule
  { name = "year"
  , pattern =
    [ Predicate $ isIntegerBetween 1000 2100
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        y <- getIntValue token
        tt $ year y
      _ -> Nothing
  }

ruleThisYear :: Rule
ruleThisYear = Rule
  { name = "this year"
  , pattern =
    [ regex "ε?φ[εέ]τος?"
    ]
  , prod = const . tt $ cycleNth TG.Year 0
  }

ruleLastYear :: Rule
ruleLastYear = Rule
  { name = "Last year"
  , pattern =
    [ regex "π[εέ]ρ(υ?σιν|ασμέν)[οόηή]ς?\\s+(έτου?ς|χρ[οό]ν(ου|ιάς?))"
    ]
  , prod = const . tt . cycleNth TG.Year $ - 1
  }

ruleLastYearOneWord :: Rule
ruleLastYearOneWord = Rule
  { name = "Last year"
  , pattern =
    [ regex "π[εέ]ρυ?σι"
    ]
  , prod = const . tt . cycleNth TG.Year $ - 1
  }

ruleNextYear :: Rule
ruleNextYear = Rule
  { name = "Last year"
  , pattern =
    [ regex "του\\s*χρόνου"
    ]
  , prod = const . tt $ cycleNth TG.Year 1
  }

ruleHhmmMilitary :: Rule
ruleHhmmMilitary = Rule
  { name = "hhmm (military)"
  , pattern =
    [ regex "((?:[01]?\\d)|(?:2[0-3]))([0-5]\\d)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (h:m:_)):_) -> do
        hh <- parseInt h
        mm <- parseInt m
        tt . mkLatent $ hourMinute False hh mm
      _ -> Nothing
  }

ruleAbsorptionOfAfterNamedDay :: Rule
ruleAbsorptionOfAfterNamedDay = Rule
  { name = "absorption of , after named day"
  , pattern =
    [ Predicate isADayOfWeek
    , regex ","
    ]
  , prod = \tokens -> case tokens of
      (x:_) -> Just x
      _ -> Nothing
  }

ruleAbsorptionOfArticleBeforeTime :: Rule
ruleAbsorptionOfArticleBeforeTime = Rule
  { name = "absorption of article before time"
  , pattern =
    [ regex "σ?τ?(α|η|ι|ο[ιυ]?|ω)ν?ς?"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleLastDayofweekOfTime :: Rule
ruleLastDayofweekOfTime = Rule
  { name = "last <day-of-week> of <time>"
  , pattern =
    [ regex "τελευταί(ου?|ας?)"
    , Predicate isADayOfWeek
    , regex "τ(ου|ης)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) -> tt $ predLastOf td1 td2
      _ -> Nothing
  }

ruleHhmmMilitaryAmpm :: Rule
ruleHhmmMilitaryAmpm = Rule
  { name = "hhmm (military) am|pm"
  , pattern =
    [ regex "((?:1[012]|0?\\d))([0-5]\\d)"
    , regex "([πμ])\\.?(μ\\.?)?"
    ]
  , prod = \tokens -> case tokens of
      ( Token RegexMatch (GroupMatch (hh:mm:_)):
        Token RegexMatch (GroupMatch (ap:_)):_) -> do
        h <- parseInt hh
        m <- parseInt mm
        tt $ timeOfDayAMPM (Text.toLower ap == "π") (hourMinute True h m)
      _ -> Nothing
  }

ruleTimeofdayTimeofdayInterval :: Rule
ruleTimeofdayTimeofdayInterval = Rule
  { name = "<time-of-day> - <time-of-day> (interval)"
  , pattern =
    [ Predicate $ and . sequence [isNotLatent, isATimeOfDay]
    , regex "\\-|μέχρι"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleDurationAfterTime :: Rule
ruleDurationAfterTime = Rule
  { name = "<duration> after <time>"
  , pattern =
    [ dimension Duration
    , regex "μετά(\\s+από)?|από"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:_:Token Time td:_) -> tt $ durationAfter dd td
      _ -> Nothing
  }

ruleOrdinalQuarter :: Rule
ruleOrdinalQuarter = Rule
  { name = "<ordinal> quarter"
  , pattern =
    [ dimension Ordinal
    , Predicate $ isGrain TG.Quarter
    ]
  , prod = \tokens -> case tokens of
      (Token Ordinal OrdinalData{TOrdinal.value = v}:_) -> tt .
        cycleNthAfter False TG.Quarter (v - 1) $ cycleNth TG.Year 0
      _ -> Nothing
  }

ruleDurationBeforeTime :: Rule
ruleDurationBeforeTime = Rule
  { name = "<duration> before <time>"
  , pattern =
    [ dimension Duration
    , regex "πριν"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:_:Token Time td:_) -> tt $ durationBefore dd td
      _ -> Nothing
  }

rulePartofdayOfTime :: Rule
rulePartofdayOfTime = Rule
  { name = "<part-of-day> of <time>"
  , pattern =
    [ Predicate isAPartOfDay
    , regex "τ(ου|ης)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) -> Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleMmddyyyy :: Rule
ruleMmddyyyy = Rule
  { name = "dd/mm/yyyy"
  , pattern =
    [ regex "(3[01]|[12]\\d|0?[1-9])[/.-](1[0-2]|0?[1-9])[/.-](\\d{2,4})"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
        y <- parseInt m3
        m <- parseInt m2
        d <- parseInt m1
        tt $ yearMonthDay y m d
      _ -> Nothing
  }

ruleTimeofdayOclock :: Rule
ruleTimeofdayOclock = Rule
  { name = "<time-of-day>  o'clock"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "η ώρα"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleDayofmonthordinalNamedmonthYear :: Rule
ruleDayofmonthordinalNamedmonthYear = Rule
  { name = "<day-of-month> ( ordinal) <named-month> year"
  , pattern =
    [ Predicate isDOMOrdinal
    , Predicate isAMonth
    , regex "(\\d{2,4})"
    ]
  , prod = \tokens -> case tokens of
      (dd:Token Time mm:Token RegexMatch (GroupMatch (yy:_)):_) -> do
        y <- parseInt yy
        dom <- intersectDOM mm dd
        Token Time <$> intersect dom (year y)
      _ -> Nothing
  }

ruleIntervalForDurationFrom :: Rule
ruleIntervalForDurationFrom = Rule
  { name = "for <duration> from <time>"
  , pattern =
    [ regex "για"
    , dimension Duration
    , regex "(ξεκινώντας\\s+)?(μετά(\\s+από)?|από)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_:Token Time td1:_) ->
        Token Time <$> interval TTime.Open td1 (durationAfter dd td1)
      _ -> Nothing
}

ruleTimezone :: Rule
ruleTimezone = Rule
  { name = "<time> timezone"
  , pattern =
    [ Predicate $ and . sequence [isNotLatent, isATimeOfDay]
    , 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 = \tokens -> case tokens of
      (Token Time td:
       Token RegexMatch (GroupMatch (tz:_)):
       _) -> Token Time <$> inTimezone (Text.toUpper tz) td
      _ -> Nothing
  }

rules :: [Rule]
rules =
  [ ruleADuration
  , ruleAbsorptionOfAfterNamedDay
  , ruleAbsorptionOfArticleBeforeTime
  , ruleAfterDuration
  , ruleAfterNextTime
  , ruleAfterTimeofday
  , ruleAfterWork
  , ruleAfternoon
  , ruleAtTimeofday
  , ruleBetweenDatetimeAndDatetimeInterval
  , ruleBetweenTimeofdayAndTimeofdayInterval
  , ruleByTheEndOfTime
  , ruleCycleCurrentLastNext
  , ruleCycleThis
  , ruleDatetimeDatetimeInterval
  , ruleDayofmonthNonOrdinalNamedmonth
  , ruleDayofmonthNonOrdinalOfNamedmonth
  , ruleDayofmonthOrdinal
  , ruleDayofmonthOrdinalNamedmonth
  , ruleDayofmonthordinalNamedmonthYear
  , ruleDurationAfterTime
  , ruleDurationBeforeTime
  , ruleDurationFromNow
  , ruleDurationHenceAgo
  , ruleEarlyMorning
  , ruleEvening
  , ruleExactlyTimeofday
  , ruleFromDatetimeDatetimeInterval
  , ruleHHMMSS
  , ruleHalfAfterIntegerHourofday
  , ruleHalfAfterIntegerHourofday2
  , ruleHenceAgoDuration
  , ruleHhmm
  , ruleHhmmMilitary
  , ruleHhmmMilitaryAmpm
  , ruleHourofdayIntegerAsRelativeMinutes
  , ruleInDuration
  , ruleInDurationFromTime
  , ruleInduringThePartofday
  , ruleIntersect
  , ruleIntersectBy
  , ruleIntersectByOfFromS
  , ruleIntervalBy
  , ruleIntervalByTheEndOf
  , ruleIntervalForDurationFrom
  , ruleIntervalTODAMPM
  , ruleIntervalTODAMPMverbose
  , ruleIntervalTODDash
  , ruleIntervalUntilTOD
  , ruleLastCycle
  , ruleLastCycleOfTime
  , ruleLastCycleOfTimeS
  , ruleLastDayofweekOfTime
  , ruleLastNCycle
  , ruleLastNight
  , ruleLastTime
  , ruleLastWeekendOfMonth
  , ruleLastYear
  , ruleLastYearOneWord
  , ruleLunch
  , ruleMidnight
  , ruleMmdd
  , ruleMmddyyyy
  , ruleMonthDdddInterval
  , ruleMorning
  , ruleNamedmonthDayofmonth
  , ruleNextCycle
  , ruleNextDayofweek
  , ruleNextNCycle
  , ruleNextTime
  , ruleNextYear
  , ruleNight
  , ruleNoon
  , ruleNthTimeAfterTime
  , ruleNthTimeOfTime
  , ruleOrdinalCycleAfterTime
  , ruleOrdinalCycleOfTime
  , ruleOrdinalQuarter
  , ruleOrdinalQuarterYear
  , rulePartOfMonth
  , rulePartofdayOfTime
  , rulePrecisionTimeofday
  , ruleQuarterBeforeOrAfterIntegerHourofday
  , ruleRelativeIntegerToOrAfterIntegerPartOfDay
  , ruleTheCycleAfterTime
  , ruleTheCycleBeforeTime
  , ruleTheCycleOfTime
  , ruleTheDayOf
  , ruleTheDayofmonthNonOrdinal
  , ruleThisCycle
  , ruleThisDayofWeek
  , ruleThisDayofWeek2
  , ruleThisPartofday
  , ruleThisYear
  , ruleTimeAfterNext
  , ruleTimePartofday
  , ruleTimeofdayAmpm
  , ruleTimeofdayAmpmVerbose
  , ruleTimeofdayApproximately
  , ruleTimeofdayLatent
  , ruleTimeofdayOclock
  , ruleTimeofdayTimeofdayInterval
  , ruleTimezone
  , ruleTomorrowNight
  , ruleTonight
  , ruleUntilTimeofdayPostfix
  , ruleWeekend
  , ruleWithinDuration
  , ruleYear
  , ruleYearLatent
  , ruleYearLatent2
  , ruleYyyymmdd
  ]
  ++ ruleDaysOfWeek
  ++ ruleHolidays
  ++ ruleInstants
  ++ ruleMonths
  ++ ruleSeasons


text:
"""
.. module: lemur.factory
    :platform: Unix
    :synopsis: This module contains all the needed functions to allow
    the factory app creation.

    :copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
    :license: Apache, see LICENSE for more details.
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>

"""
import os
import imp
import errno
import pkg_resources

from logging import Formatter
from logging.handlers import RotatingFileHandler

from flask import Flask
from lemur.common.health import mod as health
from lemur.extensions import db, migrate, principal, smtp_mail

DEFAULT_BLUEPRINTS = (
    health,
)

API_VERSION = 1

def create_app(app_name=None, blueprints=None, config=None):
    """
    Lemur application factory

    :param config:
    :param app_name:
    :param blueprints:
    :return:
    """
    if not blueprints:
        blueprints = DEFAULT_BLUEPRINTS
    else:
        blueprints = blueprints + DEFAULT_BLUEPRINTS

    if not app_name:
        app_name = __name__

    app = Flask(app_name)
    configure_app(app, config)
    configure_blueprints(app, blueprints)
    configure_extensions(app)
    configure_logging(app)
    install_plugins(app)

    @app.teardown_appcontext
    def teardown(exception=None):
        if db.session:
            db.session.remove()

    return app

def from_file(file_path, silent=False):
    """
    Updates the values in the config from a Python file.  This function
    behaves as if the file was imported as module with the

    :param file_path:
    :param silent:
    """
    d = imp.new_module('config')
    d.__file__ = file_path
    try:
        with open(file_path) as config_file:
            exec(compile(config_file.read(), file_path, 'exec'), d.__dict__)
    except IOError as e:
        if silent and e.errno in (errno.ENOENT, errno.EISDIR):
            return False
        e.strerror = 'Unable to load configuration file (%s)' % e.strerror
        raise
    return d

def configure_app(app, config=None):
    """
    Different ways of configuration

    :param app:
    :param config:
    :return:
    """
    try:
        app.config.from_envvar("LEMUR_CONF")
    except RuntimeError:
        if config and config != 'None':
            app.config.from_object(from_file(config))
        elif os.path.isfile(os.path.expanduser("~/.lemur/lemur.conf.py")):
            app.config.from_object(from_file(os.path.expanduser("~/.lemur/lemur.conf.py")))
        else:
            app.config.from_object(from_file(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'default.conf.py')))

def configure_extensions(app):
    """
    Attaches and configures any needed flask extensions
    to our app.

    :param app:
    """
    db.init_app(app)
    migrate.init_app(app, db)
    principal.init_app(app)
    smtp_mail.init_app(app)

def configure_blueprints(app, blueprints):
    """
    We prefix our APIs with their given version so that we can support
    multiple concurrent API versions.

    :param app:
    :param blueprints:
    """
    for blueprint in blueprints:
        app.register_blueprint(blueprint, url_prefix="/api/{0}".format(API_VERSION))

def configure_logging(app):
    """
    Sets up application wide logging.

    :param app:
    """
    handler = RotatingFileHandler(app.config.get('LOG_FILE', 'lemur.log'), maxBytes=10000000, backupCount=100)

    handler.setFormatter(Formatter(
        '%(asctime)s %(levelname)s: %(message)s '
        '[in %(pathname)s:%(lineno)d]'
    ))

    handler.setLevel(app.config.get('LOG_LEVEL', 'DEBUG'))
    app.logger.setLevel(app.config.get('LOG_LEVEL', 'DEBUG'))
    app.logger.addHandler(handler)

def install_plugins(app):
    """
    Installs new issuers that are not currently bundled with Lemur.

    :param settings:
    :return:
    """
    from lemur.plugins.base import register
    # entry_points={
    #    'lemur.plugins': [
    #         'verisign = lemur_verisign.plugin:VerisignPlugin'
    #     ],
    # },
    for ep in pkg_resources.iter_entry_points('lemur.plugins'):
        try:
            plugin = ep.load()
        except Exception:
            import traceback
            app.logger.error("Failed to load plugin %r:\n%s\n" % (ep.name, traceback.format_exc()))
        else:
            register(plugin)


text:
#include "SimpSMTSolver.h"

/*
inline bool isArithmeticOp( Enode * e )
{
  if ( e->isPlus    ( )
    || e->isUminus  ( )
    || e->isTimes   ( )
    || e->isLeq     ( )
    || e->isVar     ( )
    || ( e->isConstant( ) && !e->isTrue( ) && !e->isFalse( ) ) )
    return true;

  return false;
}

inline bool isUFOp( Enode * e )
{
  if ( e->isUf       ( )
    || e->isUp       ( )
    || e->isDistinct ( )
    || e->isVar      ( )
    || ( e->isConstant( ) && !e->isTrue( ) && !e->isFalse( ) ) )
    return true;

  return false;
}

void SimpSMTSolver::gatherInterfaceTerms( Enode * e )
{
  assert( config.sat_lazy_dtc != 0 );
  assert( config.logic == QF_UFIDL
       || config.logic == QF_UFLRA );

  assert( e );
  vector< Enode * > unprocessed_enodes;
  egraph.initDup1( );

  unprocessed_enodes.push_back( e );
  //
  // Visit the DAG of the term from the leaves to the root
  //
  while( !unprocessed_enodes.empty( ) )
  {
    Enode * enode = unprocessed_enodes.back( );
    //
    // Skip if the node has already been processed before
    //
    if ( egraph.isDup1( enode ) )
    {
      unprocessed_enodes.pop_back( );
      continue;
    }

    bool unprocessed_children = false;
    Enode * arg_list;
    for ( arg_list = enode->getCdr( ) ;
	  arg_list != egraph.enil ;
	  arg_list = arg_list->getCdr( ) )
    {
      Enode * arg = arg_list->getCar( );
      assert( arg->isTerm( ) );
      //
      // Push only if it is unprocessed
      //
      if ( !egraph.isDup1( arg ) )
      {
	unprocessed_enodes.push_back( arg );
	unprocessed_children = true;
      }
    }
    //
    // SKip if unprocessed_children
    //
    if ( unprocessed_children )
      continue;

    unprocessed_enodes.pop_back( );
    //
    // At this point, every child has been processed
    //
    if ( isUFOp( enode ) )
    {
      // Retrieve arguments
      for ( Enode * arg_list = enode->getCdr( )
	  ; !arg_list->isEnil( )
	  ; arg_list = arg_list->getCdr( ) )
      {
	Enode * arg = arg_list->getCar( );
	if ( isArithmeticOp( arg ) )
	  if ( interface_terms_cache.insert( arg ).second )
	  {
	    interface_terms.push_back( arg );
	    cerr << "Added: " << arg << endl;
	  }
      }
    }
    else if ( isArithmeticOp( enode ) )
    {
      // Retrieve arguments
      for ( Enode * arg_list = enode->getCdr( )
	  ; !arg_list->isEnil( )
	  ; arg_list = arg_list->getCdr( ) )
      {
	Enode * arg = arg_list->getCar( );
	if ( isUFOp( arg ) )
	  if ( interface_terms_cache.insert( arg ).second )
	  {
	    interface_terms.push_back( arg );
	    cerr << "Added: " << arg << endl;
	  }
      }
    }

    assert( !egraph.isDup1( enode ) );
    egraph.storeDup1( enode );
  }

  egraph.doneDup1( );
}
*/

// Generates a bunch of eij, and return one
Var CoreSMTSolver::generateMoreEij( )
{
  Var ret = var_Undef;

  for ( int i = 0
      ; i < (config.sat_lazy_dtc_burst < 0 ? 1 : config.sat_lazy_dtc_burst)
      ; i ++ )
  {
    Var v = generateNextEij( );
    // Return if no more eij
    if ( v == var_Undef )
      return v;
    // Save return variable
    if ( i == 0 ) ret = v;
  }

  return ret;
}

Var CoreSMTSolver::generateNextEij( )
{
  if ( egraph.getInterfaceTermsNumber( ) == 0 )
    return var_Undef;

  assert( config.sat_lazy_dtc != 0 );
  Var v = var_Undef;
  lbool pol = l_Undef;
  while ( v == var_Undef )
  {
    // Already returned all the possible eij
    if ( next_it_i == egraph.getInterfaceTermsNumber( ) - 1
      && next_it_j == egraph.getInterfaceTermsNumber( ) )
      return var_Undef;

    // Get terms
    // Enode * i = interface_terms[ next_it_i ];
    // Enode * j = interface_terms[ next_it_j ];
    Enode * i = egraph.getInterfaceTerm( next_it_i );
    Enode * j = egraph.getInterfaceTerm( next_it_j );
    // Increase counters
    next_it_j ++;
    if ( next_it_j == next_it_i ) next_it_j ++;
    // if ( next_it_j == static_cast< int >( interface_terms.size( ) ) )
    if ( next_it_j == egraph.getInterfaceTermsNumber( ) )
    {
      next_it_i ++;
      next_it_j = next_it_i + 1;
    }
    // No need to create eij if both numbers,
    // it's either trivially true or false
    if ( i->isConstant( )
      && j->isConstant( ) )
      continue;

    if ( config.logic == QF_UFLRA
      || config.logic == QF_UFIDL )
    {
      //
      // Since arithmetic solvers do not
      // understand equalities, produce
      // the splitted versions of equalities
      // and add linking clauses
      //
      Enode * eij = egraph.mkEq( egraph.cons( i, egraph.cons( j ) ) );

      if ( config.verbosity > 2 )
	cerr << "# CoreSMTSolver::Adding eij: " << eij << endl;

      if ( eij->isTrue( ) || eij->isFalse( ) ) continue;
      // Canonize
      LAExpression la( eij );
      Enode * eij_can = la.toEnode( egraph );
      // Continue if already generated equality
      // if ( !interface_equalities.insert( eij_can ).second ) continue;
      if ( eij_can->isTrue( ) || eij_can->isFalse( ) ) continue;
      v = theory_handler->enodeToVar( eij );
      // Created one equality that is already assigned
      // Skip it
      if ( value( v ) != l_Undef )
      {
	v = var_Undef;
	continue;
      }
      // Get lhs and rhs
      Enode * lhs = eij_can->get1st( );
      Enode * rhs = eij_can->get2nd( );
      Enode * leq = egraph.mkLeq( egraph.cons( lhs, egraph.cons( rhs ) ) );
      // Canonize lhs
      LAExpression b( leq );
      leq = b.toEnode( egraph );
      // Canonize rhs
      Enode * geq = egraph.mkGeq( egraph.cons( lhs, egraph.cons( rhs ) ) );
      LAExpression c( geq );
      geq = c.toEnode( egraph );
      // Add clause ( !x=y v x<=y )
      vector< Enode * > clause;
      clause.push_back( egraph.mkNot( egraph.cons( eij ) ) );
      clause.push_back( leq );
      addSMTAxiomClause( clause );
      // Add clause ( !x=y v x>=y )
      clause.pop_back( );
      clause.push_back( geq );
      addSMTAxiomClause( clause );
      // Add clause ( x=y v !x>=y v !x<=y )
      clause.clear( );
      clause.push_back( eij );
      clause.push_back( egraph.mkNot( egraph.cons( leq ) ) );
      clause.push_back( egraph.mkNot( egraph.cons( geq ) ) );
      addSMTAxiomClause( clause );

      pol = theory_handler->evaluate( eij );
      if ( pol == l_Undef ) pol = theory_handler->evaluate( leq );
      if ( pol == l_Undef ) pol = theory_handler->evaluate( geq );
    }
    else
    {
      Enode * eij = egraph.mkEq( egraph.cons( i, egraph.cons( j ) ) );
      // Continue if already generated equality
      if ( !interface_equalities.insert( eij ).second ) continue;
      if ( eij->isTrue( ) || eij->isFalse( ) ) continue;
      // Add new atom and get variable
      v = theory_handler->enodeToVar( eij );
      // Initialize congruence data structure
      egraph.initializeCong( eij );
    }
  }
#ifdef STATISTICS
  ie_generated ++;
#endif
  assert( v != var_Undef );
  assert( polarity.size( ) > v );
  // Assign to false first. We merge the least possible
  // Alternatively we can merge the most, or
  polarity[ v ] = ( pol == l_True
                    ? false
		    : ( pol == l_False
		        ? true
			: true ) );

  return v;
}