text: """
  Helper functions to make gof backwards compatible
  
  (tested on python 2.4 and 2.5)
  """
  
  import collections
  import sys
  
  
  if sys.version_info[:2] < (2, 5):
  
      def all(iterable):
          for element in iterable:
              if not element:
                  return False
          return True
  
      def any(iterable):
          for element in iterable:
              if element:
                  return True
          return False
  
      def partial(func, *args, **keywords):
          def newfunc(*fargs, **fkeywords):
              newkeywords = keywords.copy()
              newkeywords.update(fkeywords)
              return func(*(args + fargs), **newkeywords)
          newfunc.func = func
          newfunc.args = args
          newfunc.keywords = keywords
          return newfunc
  
      class deque(collections.deque):
          """
          Custom deque class to implement the `remove` method.
          """
          def remove(self, item):
              found = None
              for i, x in enumerate(self):
                  if x == item:
                      found = i
                      break
              if found is None:
                  raise ValueError('item not found in deque')
              # To remove an item, we rotate the queue until it is the first item
              # in the queue, we pop it, and finally we rotate back the queue.
              self.rotate(-found)
              self.popleft()
              self.rotate(found)
  
      class defaultdict(dict):
          def __init__(self, default_factory=None, *a, **kw):
              if (default_factory is not None and
                  not hasattr(default_factory, '__call__')):
                  raise TypeError('first argument must be callable')
              dict.__init__(self, *a, **kw)
              self.default_factory = default_factory
  
          def __getitem__(self, key):
              try:
                  return dict.__getitem__(self, key)
              except KeyError:
                  return self.__missing__(key)
  
          def __missing__(self, key):
              if self.default_factory is None:
                  raise KeyError(key)
              self[key] = value = self.default_factory()
              return value
  
          def __reduce__(self):
              if self.default_factory is None:
                  args = tuple()
              else:
                  args = self.default_factory,
              # consider replacing items() with iteritems()
              return type(self), args, None, None, self.items()
  
          def copy(self):
              return self.__copy__()
  
          def __copy__(self):
              return type(self)(self.default_factory, self)
  
          def __deepcopy__(self, memo):
              import copy
              return type(self)(self.default_factory,
                                copy.deepcopy(self.items()))
  
          def __repr__(self):
              return 'defaultdict(%s, %s)' % (self.default_factory,
                                              dict.__repr__(self))
  
  else:
      # Only bother with this else clause and the __all__ line if you are putting
      # this in a separate file.
      import __builtin__
      all = __builtin__.all
      any = __builtin__.any
      import collections
      import functools
      partial = functools.partial
      defaultdict = collections.defaultdict
      deque = collections.deque
  
  __all__ = ['all', 'any']
  
  if sys.version_info[:2] < (2, 6):
      # Borrowed from Python docs
      def combinations(iterable, r):
          # combinations('ABCD', 2) --> AB AC AD BC BD CD
          # combinations(range(4), 3) --> 012 013 023 123
          pool = tuple(iterable)
          n = len(pool)
          if r > n:
              return
          indices = range(r)
          yield tuple(pool[i] for i in indices)
          while True:
              for i in reversed(range(r)):
                  if indices[i] != i + n - r:
                      break
              else:
                  return
              indices[i] += 1
              for j in range(i + 1, r):
                  indices[j] = indices[j - 1] + 1
              yield tuple(pool[i] for i in indices)
  
      def product(*args, **kwds):
          # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
          # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
          pools = map(tuple, args) * kwds.get('repeat', 1)
          result = [[]]
          for pool in pools:
              result = [x + [y] for x in result for y in pool]
          for prod in result:
              yield tuple(prod)
  
      # For maxsize
      class __Dummy(object):
          """
          Dummy class used to know what is the max index of a slice.
  
          This way, we do not have to rely on guesses for untested
          architectures.
          """
          def __getslice__(self, *args):
              return args
  
      # This "slice" should be a (1, maxsize) tuple
      __dummy_slice = __Dummy()[1:]
      maxsize = __dummy_slice[1]
      del __dummy_slice, __Dummy
  
  else:
      from itertools import combinations, product
      from sys import maxsize
  
  
  if sys.version_info[:2] < (2, 7):
      # The following implementation of OrderedDict compatible with python 2.4
      # was taked from http://pypi.python.org/pypi/ordereddict/1.1
      # It is under the MIT license.
  
      # Copyright (c) 2009 Raymond Hettinger
      #
      # Permission is hereby granted, free of charge, to any person
      # obtaining a copy of this software and associated documentation files
      # (the "Software"), to deal in the Software without restriction,
      # including without limitation the rights to use, copy, modify, merge,
      # publish, distribute, sublicense, and/or sell copies of the Software,
      # and to permit persons to whom the Software is furnished to do so,
      # subject to the following conditions:
      #
      #     The above copyright notice and this permission notice shall be
      #     included in all copies or substantial portions of the Software.
      #
      #     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      #     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
      #     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      #     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      #     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      #     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      #     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      #     OTHER DEALINGS IN THE SOFTWARE.
      from UserDict import DictMixin
  
      class OrderedDict(dict, DictMixin):
  
          def __init__(self, *args, **kwds):
              if len(args) > 1:
                  raise TypeError('expected at most 1 arguments, got %d' %
                                  len(args))
              try:
                  self.__end
              except AttributeError:
                  self.clear()
              self.update(*args, **kwds)
  
          def clear(self):
              self.__end = end = []
              end += [None, end, end]      # sentinel node for doubly linked list
              self.__map = {}              # key --> [key, prev, next]
              dict.clear(self)
  
          def __setitem__(self, key, value):
              if key not in self:
                  end = self.__end
                  curr = end[1]
                  curr[2] = end[1] = self.__map[key] = [key, curr, end]
              dict.__setitem__(self, key, value)
  
          def __delitem__(self, key):
              dict.__delitem__(self, key)
              key, prev, next = self.__map.pop(key)
              prev[2] = next
              next[1] = prev
  
          def __iter__(self):
              end = self.__end
              curr = end[2]
              while curr is not end:
                  yield curr[0]
                  curr = curr[2]
  
          def __reversed__(self):
              end = self.__end
              curr = end[1]
              while curr is not end:
                  yield curr[0]
                  curr = curr[1]
  
          def popitem(self, last=True):
              if not self:
                  raise KeyError('dictionary is empty')
              if last:
                  key = reversed(self).next()
              else:
                  key = iter(self).next()
              value = self.pop(key)
              return key, value
  
          def __reduce__(self):
              items = [[k, self[k]] for k in self]
              tmp = self.__map, self.__end
              del self.__map, self.__end
              inst_dict = vars(self).copy()
              self.__map, self.__end = tmp
              if inst_dict:
                  return (self.__class__, (items,), inst_dict)
              return self.__class__, (items,)
  
          def keys(self):
              return list(self)
  
          setdefault = DictMixin.setdefault
          update = DictMixin.update
          pop = DictMixin.pop
          values = DictMixin.values
          items = DictMixin.items
          iterkeys = DictMixin.iterkeys
          itervalues = DictMixin.itervalues
          iteritems = DictMixin.iteritems
  
          def __repr__(self):
              if not self:
                  return '%s()' % (self.__class__.__name__,)
              return '%s(%r)' % (self.__class__.__name__, self.items())
  
          def copy(self):
              return self.__class__(self)
  
          @classmethod
          def fromkeys(cls, iterable, value=None):
              d = cls()
              for key in iterable:
                  d[key] = value
              return d
  
          def __eq__(self, other):
              if isinstance(other, OrderedDict):
                  if len(self) != len(other):
                      return False
                  for p, q in  zip(self.items(), other.items()):
                      if p != q:
                          return False
                  return True
              return dict.__eq__(self, other)
  
      def __ne__(self, other):
          return not self == other
  
  else:
      from UserDict import DictMixin
      OrderedDict = collections.OrderedDict
      from collections import Callable
  
  
  class DefaultOrderedDict(OrderedDict):
      def __init__(self, default_factory=None, *a, **kw):
          if (default_factory is not None and
              not callable(default_factory)):
              raise TypeError('first argument must be callable')
          OrderedDict.__init__(self, *a, **kw)
          self.default_factory = default_factory
  
      def __getitem__(self, key):
          try:
              return OrderedDict.__getitem__(self, key)
          except KeyError:
              return self.__missing__(key)
  
      def __missing__(self, key):
          if self.default_factory is None:
              raise KeyError(key)
          self[key] = value = self.default_factory()
          return value
  
      def __reduce__(self):
          if self.default_factory is None:
              args = tuple()
          else:
              args = self.default_factory,
          return type(self), args, None, None, self.items()
  
      def copy(self):
          return self.__copy__()
  
      def __copy__(self):
          return type(self)(self.default_factory, self)
  