text: from zipline.errors import (
      CalendarNameCollision,
      CyclicCalendarAlias,
      InvalidCalendarName,
  )
  from zipline.utils.calendars.exchange_calendar_cfe import CFEExchangeCalendar
  from zipline.utils.calendars.exchange_calendar_ice import ICEExchangeCalendar
  from zipline.utils.calendars.exchange_calendar_nyse import NYSEExchangeCalendar
  from zipline.utils.calendars.exchange_calendar_cme import CMEExchangeCalendar
  from zipline.utils.calendars.exchange_calendar_bmf import BMFExchangeCalendar
  from zipline.utils.calendars.exchange_calendar_lse import LSEExchangeCalendar
  from zipline.utils.calendars.exchange_calendar_tsx import TSXExchangeCalendar
  from zipline.utils.calendars.us_futures_calendar import (
      QuantopianUSFuturesCalendar,
  )
  from zipline.utils.calendars.exchange_calendar_cfx import CustomForexExchangeCalendar
  
  _default_calendar_factories = {
      'NYSE': NYSEExchangeCalendar,
      'CME': CMEExchangeCalendar,
      'ICE': ICEExchangeCalendar,
      'CFE': CFEExchangeCalendar,
      'BMF': BMFExchangeCalendar,
      'LSE': LSEExchangeCalendar,
      'TSX': TSXExchangeCalendar,
      'us_futures': QuantopianUSFuturesCalendar,
      'CFX': CustomForexExchangeCalendar,
  }
  _default_calendar_aliases = {
      'NASDAQ': 'NYSE',
      'BATS': 'NYSE',
      'CBOT': 'CME',
      'COMEX': 'CME',
      'NYMEX': 'CME',
      'ICEUS': 'ICE',
      'NYFE': 'ICE',
  }
  default_calendar_names = sorted(_default_calendar_factories.keys())
  
  
  class TradingCalendarDispatcher(object):
      """
      A class for dispatching and caching trading calendars.
  
      Methods of a global instance of this class are provided by
      zipline.utils.calendar_utils.
  
      Parameters
      ----------
      calendars : dict[str -> TradingCalendar]
          Initial set of calendars.
      calendar_factories : dict[str -> function]
          Factories for lazy calendar creation.
      aliases : dict[str -> str]
          Calendar name aliases.
      """
      def __init__(self, calendars, calendar_factories, aliases):
          self._calendars = calendars
          self._calendar_factories = calendar_factories
          self._aliases = aliases
  
      def get_calendar(self, name):
          """
          Retrieves an instance of an TradingCalendar whose name is given.
  
          Parameters
          ----------
          name : str
              The name of the TradingCalendar to be retrieved.
  
          Returns
          -------
          calendar : zipline.utils.calendars.TradingCalendar
              The desired calendar.
          """
          canonical_name = self.resolve_alias(name)
  
          try:
              return self._calendars[canonical_name]
          except KeyError:
              # We haven't loaded this calendar yet, so make a new one.
              pass
  
          try:
              factory = self._calendar_factories[canonical_name]
          except KeyError:
              # We don't have a factory registered for this name.  Barf.
              raise InvalidCalendarName(calendar_name=name)
  
          # Cache the calendar for future use.
          calendar = self._calendars[canonical_name] = factory()
          return calendar
  
      def has_calendar(self, name):
          """
          Do we have (or have the ability to make) a calendar with ``name``?
          """
          return (
              name in self._calendars
              or name in self._calendar_factories
              or name in self._aliases
          )
  
      def register_calendar(self, name, calendar, force=False):
          """
          Registers a calendar for retrieval by the get_calendar method.
  
          Parameters
          ----------
          name: str
              The key with which to register this calendar.
          calendar: TradingCalendar
              The calendar to be registered for retrieval.
          force : bool, optional
              If True, old calendars will be overwritten on a name collision.
              If False, name collisions will raise an exception.
              Default is False.
  
          Raises
          ------
          CalendarNameCollision
              If a calendar is already registered with the given calendar's name.
          """
          if force:
              self.deregister_calendar(name)
  
          if self.has_calendar(name):
              raise CalendarNameCollision(calendar_name=name)
  
          self._calendars[name] = calendar
  
      def register_calendar_type(self, name, calendar_type, force=False):
          """
          Registers a calendar by type.
  
          This is useful for registering a new calendar to be lazily instantiated
          at some future point in time.
  
          Parameters
          ----------
          name: str
              The key with which to register this calendar.
          calendar_type: type
              The type of the calendar to register.
          force : bool, optional
              If True, old calendars will be overwritten on a name collision.
              If False, name collisions will raise an exception.
              Default is False.
  
          Raises
          ------
          CalendarNameCollision
              If a calendar is already registered with the given calendar's name.
          """
          if force:
              self.deregister_calendar(name)
  
          if self.has_calendar(name):
              raise CalendarNameCollision(calendar_name=name)
  
          self._calendar_factories[name] = calendar_type
  
      def register_calendar_alias(self, alias, real_name, force=False):
          """
          Register an alias for a calendar.
  
          This is useful when multiple exchanges should share a calendar, or when
          there are multiple ways to refer to the same exchange.
  
          After calling ``register_alias('alias', 'real_name')``, subsequent
          calls to ``get_calendar('alias')`` will return the same result as
          ``get_calendar('real_name')``.
  
          Parameters
          ----------
          alias : str
              The name to be used to refer to a calendar.
          real_name : str
              The canonical name of the registered calendar.
          force : bool, optional
              If True, old calendars will be overwritten on a name collision.
              If False, name collisions will raise an exception.
              Default is False.
          """
          if force:
              self.deregister_calendar(alias)
  
          if self.has_calendar(alias):
              raise CalendarNameCollision(calendar_name=alias)
  
          self._aliases[alias] = real_name
  
          # Ensure that the new alias doesn't create a cycle, and back it out if
          # we did.
          try:
              self.resolve_alias(alias)
          except CyclicCalendarAlias:
              del self._aliases[alias]
              raise
  
      def resolve_alias(self, name):
          """
          Resolve a calendar alias for retrieval.
  
          Parameters
          ----------
          name : str
              The name of the requested calendar.
  
          Returns
          -------
          canonical_name : str
              The real name of the calendar to create/return.
          """
          # Use an OrderedDict as an ordered set so that we can return the order
          # of aliases in the event of a cycle.
          seen = []
  
          while name in self._aliases:
              seen.append(name)
              name = self._aliases[name]
  
              # This is O(N ** 2), but if there's an alias chain longer than 2,
              # something strange has happened.
              if name in seen:
                  seen.append(name)
                  raise CyclicCalendarAlias(
                      cycle=" -> ".join(repr(k) for k in seen)
                  )
  
          return name
  
      def deregister_calendar(self, name):
          """
          If a calendar is registered with the given name, it is de-registered.
  
          Parameters
          ----------
          cal_name : str
              The name of the calendar to be deregistered.
          """
          self._calendars.pop(name, None)
          self._calendar_factories.pop(name, None)
          self._aliases.pop(name, None)
  
      def clear_calendars(self):
          """
          Deregisters all current registered calendars
          """
          self._calendars.clear()
          self._calendar_factories.clear()
          self._aliases.clear()
  
  
  # We maintain a global calendar dispatcher so that users can just do
  # `register_calendar('my_calendar', calendar) and then use `get_calendar`
  # without having to thread around a dispatcher.
  global_calendar_dispatcher = TradingCalendarDispatcher(
      calendars={},
      calendar_factories=_default_calendar_factories,
      aliases=_default_calendar_aliases,
  )
  
  get_calendar = global_calendar_dispatcher.get_calendar
  clear_calendars = global_calendar_dispatcher.clear_calendars
  deregister_calendar = global_calendar_dispatcher.deregister_calendar
  register_calendar = global_calendar_dispatcher.register_calendar
  register_calendar_type = global_calendar_dispatcher.register_calendar_type
  register_calendar_alias = global_calendar_dispatcher.register_calendar_alias
  