    DEBUG_TOOLBAR = True
    DEBUG_TOOLBAR = False
    SENTRY_SUPPORT = True
    SENTRY_SUPPORT = False
def get_app(): class BlockerRecord(app.db.EmbeddedDocument):
    """
    Represents a blockage of work for a card.
    """

    reason = app.db.StringField(required=True)
    """The reason why the card was considered blocked."""

    blocked_at = app.db.DateTimeField(required=True)
    """When the card's blockage started."""

    unblocked_at = app.db.DateTimeField(required=False)
    """When the card's blockage stopped."""

    @property
    def duration(self):
        if self.unblocked_at is not None:
            unblocked_at = self.unblocked_at
        else:
            unblocked_at = now()
        delta = unblocked_at - self.blocked_at
        return delta_in_hours(delta) class States(object):
    def __init__(self, config=None):
        if not config:
            config = app.config
        self.config = config
        self.states = self._parse_state_config(config.get('CARD_STATES', ()))
        self.state_names = [s.name for s in self.states]
        self.backlog_state = self._find_backlog()
        self.start_state = self._find_start()
        self.done_state = self._find_done()
        self.pre_start = self._find_pre_start()
        self.in_progress = self._find_in_progress()

        self.backlog = self.backlog_state.name
        self.start = self.start_state.name
        self.done = self.done_state.name

    def _parse_state_config(self, config):
        states = []
        for item in config:
            if isinstance(item, tuple):
                s = State(
                    name=item[0],
                    buffer=item[1],
                    is_buffer=False,
                )
                sb = State(
                    name=item[1],
                    buffer=None,
                    is_buffer=True
                )
                states.append(s)
                states.append(sb)
            else:
                s = State(
                    name=item,
                    buffer=None,
                    is_buffer=False,
                )
                states.append(s)
        return states

    def _find_pre_start(self):
        """
        Find all states, in order, that come
        before a start_date is applied.
        """
        return [s.name for s in self.states if self.states.index(s) < self.states.index(self.start_state)]

    def _find_in_progress(self):
        """
        Find all states, in order, that come after after backlog
        but before done.
        """
        in_progress = [s.name for s in self.states
            if self.states.index(s) > self.states.index(self.backlog_state) and
            self.states.index(s) < self.states.index(self.done_state)]
        return in_progress

    def _find_done(self):
        default = -1
        done = self.config.get('DONE_STATE', default)
        return self.states[done]

    def _find_start(self):
        default = 1
        start = self.config.get('START_STATE', default)
        return self.states[start]

    def _find_backlog(self):
        default = 0
        backlog = self.config.get('BACKLOG_STATE', default)
        return self.states[backlog]

    def __iter__(self):
        for state in self.states:
            yield state.name

    def __unicode__(self):
        return unicode([unicode(s) for s in self])

    def __str__(self):
        return str([str(s) for s in self])

    def __getitem__(self, key):
        return self.states[key].name

    def index(self, arg):
        """
        The index method routes requests for strings
        differently than requests for the new in 1.12 State objects.
        """
        if isinstance(arg, (str, unicode)):
            return self.state_names.index(arg)
        else:
            return self.states.index(arg)

    def find_by_slug(self, slug):
        by_slug = {}
        for state in self:
            by_slug[slugify(state)] = state
        return by_slug[slug]

    @property
    def orderable(self):
        orderable = [self._find_backlog().name, ]
        for state in self.config.get('FUNNEL_VIEWS', {}).keys():
            if state in list(self):
                orderable.append(state)
        return list(set(orderable))

    @property
    def for_forms(self):
        form_list = [('', ''), ]  # Add a blank
        form_list.extend([(state.name, state.name) for state in self.states])
        return tuple(form_list)

    @property
    def active(self):
        active = []
        for state in self.states:
            if state.is_buffer is False:
                active.append(state)
        return active def set_due_date_from_ticket(kard, ticket): def now():
    return datetime.datetime.now() def days_between(date1, date2):
    if date1 < date2:
        oldest_date, youngest_date = date1, date2
    else:
        oldest_date, youngest_date = date2, date1

    delta = youngest_date - oldest_date

    days = delta.days
    partial_days = ((delta.seconds / 60) / 60) / 24.0

    diff_in_days = float(days + partial_days)

    return int(round(diff_in_days)) def make_end_date(year=None, month=None, day=None, date=None):
    end_date = munge_date(year, month, day, date)
    end_date = end_date.replace(hour=23, minute=59, second=59)
    return end_date def make_start_date(year=None, month=None, day=None, date=None):
    start_date = munge_date(year, month, day, date)
    start_date = start_date.replace(hour=23, minute=59, second=59)
    start_date = start_date.replace(hour=0, minute=0, second=0)
    return start_date def munge_date(year=None, month=None, day=None, date=None):
    """
    Takes a given datetime, or now(), and sets its
    year, month and day to any of those values passed in
    optionally.
    """
    if not date:
        date = datetime.datetime.now()

    year = year or date.year
    month = month or date.month
    day = day or date.day

    date = date.replace(year=year, month=month, day=day, microsecond=0)
    return date def month_range(date):
    start = date.replace(day=1)
    end = start + relativedelta(months=+1) + relativedelta(days=-1)

    start, end = make_start_date(date=start), make_end_date(date=end)
    return start, end def week_range(date):
    day_type = date.isoweekday()  # 1-7
    if day_type == 7:
        start_date = date
    else:
        start_date = date - relativedelta(days=day_type)
    end_date = start_date + relativedelta(days=6)

    start_date = make_start_date(date=start_date)
    end_date = make_end_date(date=end_date)

    return start_date, end_date def average(values):
    """Computes the arithmetic mean of a list of numbers.

    >>> print average([20, 30, 70])
    40.0
    """
    try:
        return stats.mean(values)
    except ZeroDivisionError:
        return None def standard_deviation(values):
    try:
        return stats.stdev(values)
    except ZeroDivisionError:
        return None def median(values):
    try:
        return stats.median(values)
    except (ValueError, UnboundLocalError):
        return None
import importlib
import datetime
import math
from dateutil.relativedelta import relativedelta
from collections import namedtuple
from kardboard.app import app
from mongoengine.queryset import Q
from flask.ext.mongoengine import QuerySet
from kardboard.models.blocker import BlockerRecord
from kardboard.models.states import States
from kardboard.services import ticketdatasync
from kardboard.util import (
    now,
    days_between,
    make_end_date,
    make_start_date,
    munge_date,
    month_range,
    week_range,
    average,
    standard_deviation,
    median,
)
            from kardboard.models.statelog import StateLog
            from kardboard.tasks import update_flow_reports

        ordered_backlog_cards = self.filter(ordered_backlog_q).order_by('priority', 'created_at')
        ordered_backlog_cards = ordered_backlog_cards.limit(backlog_limit).exclude('_ticket_system_data')
        unordered_backlog_cards = []
        if len(ordered_backlog_cards) < backlog_limit:
            ordered_backlog_cards = list(ordered_backlog_cards)
            unordered_backlog_cards = Kard.objects.filter(unordered_backlog_q).order_by('created_at')
            unordered_backlog_cards = unordered_backlog_cards.limit(backlog_limit).exclude('_ticket_system_data')

        backlog = list(ordered_backlog_cards) + list(unordered_backlog_cards)
        backlog = backlog[:backlog_limit]

        return backlog + wip_and_done


class Kard(app.db.Document):
    """
    Represents a card on a Kanban board.
    """
    _ticket_system = None

    key = app.db.StringField(required=True, unique=True)
    """A unique string that matches a Kard up to a ticket in a parent system."""

    title = app.db.StringField()
    backlog_date = app.db.DateTimeField(required=True)
    """When the card entered the backlog."""

    start_date = app.db.DateTimeField()
    """When the card was started."""

    done_date = app.db.DateTimeField()
    """When the card was completed."""

    _cycle_time = app.db.IntField(db_field="cycle_time")
    _lead_time = app.db.IntField(db_field="lead_time")
    team = app.db.StringField(required=True, default="")
    """A selection from a user supplied list of teams/assignees. See :ref:`CARD_TEAMS`"""

    state = app.db.StringField(required=True, default="Unknown")
    """Which column on the kanban board the card is in."""
    priority = app.db.IntField(required=False)
    """Used when ordering cards in the backlog."""

    blocked = app.db.BooleanField(default=False)
    """Is the card currently blocked."""

    blocked_ever = app.db.BooleanField(default=False)
    """Was the card ever blocked in its history."""

    blocked_time = app.db.IntField(required=False)
    """How long the card has been blocked in its history"""

    blockers = app.db.ListField(
        app.db.EmbeddedDocumentField(BlockerRecord),
    )

    created_at = app.db.DateTimeField(required=True)

    due_date = app.db.DateTimeField(required=False)

    _time_in_current_state = app.db.FloatField(required=False, db_field="time_in_current_state")
    _service_class = app.db.StringField(required=False, db_field="service_class")
    _type = app.db.StringField(required=False)
    _assignee = app.db.StringField(db_field="assignee")
    _worked_on = app.db.ListField(
        field=app.db.StringField(required=False),
        required=False
    )
    _version = app.db.StringField(required=False, db_field="version")

    _ticket_system_updated_at = app.db.DateTimeField()
    _ticket_system_data = app.db.DictField()

    meta = {
        'queryset_class': KardQuerySet,
        'collection': 'kard',
        'ordering': ['-due_date', '+priority', '-backlog_date'],
        'auto_create_index': True,
        'indexes': [('state', 'team'), ('team', 'done_date'), 'team', '_type', '_service_class', '_cycle_time', '_lead_time', 'due_date'],
    }

    EXPORT_FIELDNAMES = (
        'key',
        'title',
        'backlog_date',
        'start_date',
        'done_date',
        'state',
    )

    @property
    def service_class(self):
        if self._service_class:
            classdef = app.config.get('SERVICE_CLASSES', {}).get(
                self._service_class, {})
        else:
            classdef = app.config.get('SERVICE_CLASSES', {}).get(
                'default', {})

        service_class = {
            'name': classdef.get('name', ''),
            'upper': classdef.get('upper', ''),
            'lower': classdef.get('lower', ''),
            'wip': classdef.get('wip', ''),
        }
        return service_class

    def _convert_dates_to_datetimes(self, date):
        if not date:
            return None
        if not hasattr(date, "hour"):
            return datetime.datetime(date.year, date.month, date.day,
                23, 59, 59, 0)
        return date

    def block(self, reason, blocked_at=None):
        if not blocked_at:
            blocked_at = datetime.datetime.now()


        b = BlockerRecord(