text: from __future__ import unicode_literals
  
  import datetime
  from calendar import monthrange
  
  from django.db import models
  from django.db.models import Q
  from django.utils.timezone import make_aware, get_default_timezone
  
  
  class EventManager(models.Manager):
      def _get_kwargs(self, category, tag):
          """Helper function for getting category/tag kwargs."""
          vals = {
              'categories__title__iexact': category,
              'tags__name__iexact': tag
          }
          kwargs = {}
          for k, v in vals.items():
              if v:
                  kwargs[k] = v
          return kwargs
  
      @staticmethod
      def get_first_and_last(year, month):
          """Returns two datetimes: first day and last day of given year&month"""
          ym_first = make_aware(
              datetime.datetime(year, month, 1),
              get_default_timezone()
          )
          ym_last = make_aware(
              datetime.datetime(year, month, monthrange(year, month)[1], 23, 59, 59, 1000000-1),
              get_default_timezone()
          )
          return ym_first, ym_last
  
      def all_month_events(self, year, month, category=None, tag=None,
                           loc=False, cncl=False):
          """
          Returns all events that have an occurrence within the given
          month & year.
          """
          kwargs = self._get_kwargs(category, tag)
          ym_first, ym_last = self.get_first_and_last(year, month)
  
          pref = []
          if loc:
              pref.append("location")
          if cncl:
              pref.append("cancellations")
  
          # for yearly repeat, we need to check the start and end date months
          # b/c yearly events should occur every year in the same month
          r = Q(repeat="YEARLY")
          dstart_mo = Q(start_date__month=month)
          dend_mo = Q(end_date__month=month)
  
          dstart_yr = Q(start_date__year=year)
          dend_yr = Q(end_date__year=year)
  
          return self.model.objects.filter(
              # only events that are still repeating
              r & (dstart_mo | dend_mo) |  # yearly repeat
              (~Q(repeat="NEVER")) |  # all other repeats
              ((dstart_yr | dend_yr) & (dstart_mo | dend_yr)),  # non-repeating
              Q(end_repeat=None) | Q(end_repeat__gte=ym_first),
              start_date__lte=ym_last  # no events that haven't started yet
          ).filter(**kwargs).prefetch_related(*pref).order_by('start_date').distinct()
  
  #    XXX These are no longer used since all_month_events() (above) was created.
  #    def month_events(self, year, month, category=None, tag=None):
  #        """
  #        Returns the events within the given month and year. If category
  #        and/or tag is given, the events returned will have
  #        those categories/tags.
  #        """
  #        kwargs = self._get_kwargs(category, tag)
  #        return self.model.objects.within(year, month).filter(
  #            **kwargs).prefetch_related('location', 'cancellations')
  #
  #    def within(self, year, month):
  #        """Returns events within the given year and month."""
  #        return self.model.objects.filter(
  #            Q(start_date__year=year) | Q(end_date__year=year),
  #            Q(start_date__month=month) | Q(end_date__month=month)
  #        )
  
      def live(self, now):
          """
          Returns a queryset of events that will occur again after 'now'.
          Used to help generate a list of upcoming events.
          """
          return self.model.objects.filter(
              Q(end_repeat=None) | Q(end_repeat__gte=now) |
              Q(start_date__gte=now) | Q(end_date__gte=now)
          ).exclude(  # exclude single day events that won't occur again
              start_date__lt=now, end_date__lt=now,
              repeat="NEVER", end_repeat=None,
          ).prefetch_related('cancellations')
  