text: """Provides an interface for determining how Python objects are serialized and de-serialized."""
  import threading
  
  from amfast import AmFastError
  
  class ClassDefError(AmFastError):
      """ClassDef related errors."""
      pass
  
  class ClassDef(object):
      """Defines how objects of a given class are serialized and de-serialized.
      This class can be sub-classed to provide custom serialization.
  
      attributes
      ===========
       * class_ - class, the class object mapped to this definition
       * alias - string, the AMF alias name of the mapped class
       * static_attrs - tuple or list, a tuple of static attribute names,
            all values must be strings or unicode.
       * amf3 - bool, if True, this object will be encoded in AMF3.
       * encode_types - dict, keys = attribute names, values = callables.
           Callables must accept a single parameter
           (the object being encoded) and return a new object.
       * decode_types - dict, keys = attribute names, values = callables.
           Callables must accept a single parameter
           (the object being decoded) and return a new object.
  
      """
  
      CLASS_DEF = True
  
      def __init__(self, class_, alias=None, static_attrs=None,
          amf3=None, encode_types=None, decode_types=None, _built_in=False):
          """arguments
          =============
           * class_ - class, the class being mapped.
           * alias - string, specifies the amf class alias. Default = module.class
           * static_attrs - tuple or list, a tuple of static attribute strings. Default = empty tuple
           * amf3 - bool, if True, this object will be encoded in AMF3. Default = True
           * encode_types - dict, keys = attribute names, values = callables. Default = None
           * decode_types - dict, keys = attribute names, values = callables. Default = None
          """
          self.class_ = class_
          self._built_in = _built_in
  
          if alias is None:
              if hasattr(class_, ALIAS):
                  alias = getattr(class_, ALIAS)
              else:
                  alias = '.'.join((class_.__module__, class_.__name__))
          self.alias = alias
  
          if static_attrs is None:
              if hasattr(class_, STATIC_ATTRS):
                  static_attrs = self.static_attrs = getattr(class_, STATIC_ATTRS)
              else: 
                  static_attrs = () 
          self.static_attrs = static_attrs
  
          if amf3 is None:
              if hasattr(class_, AMF3):
                  amf3 = getattr(class_, AMF3)
              else:
                  amf3 = True
          self.amf3 = amf3
  
          self.encode_types = encode_types
          self.decode_types = decode_types
  
      def getStaticAttrVals(self, obj):
          """Returns a list of values of attributes defined in self.static_attrs
  
          If this method is overridden to provide custom behavior, please note:
          Returned values MUST BE IN THE SAME ORDER AS THEY APPEAR IN self.static_attrs.
  
          arguments
          ==========
           * obj - object, the object to get attribute values from.
          """
          return [getattr(obj, attr, None) for attr in self.static_attrs]
  
      def getInstance(self):
          """Returns an instance of the mapped class to be used 
          when an object of this type is deserialized.
          """
          return self.class_.__new__(self.class_)
  
      def applyAttrVals(self, obj, vals):
          """Set decoded attribute values on the object.
  
          arguments
          ==========
           * obj - object, the object to set the attribute values on.
           * vals - dict, keys == attribute name, values == attribute values.
          """
          [setattr(obj, key, val) for key, val in vals.iteritems()]
  
  class DynamicClassDef(ClassDef):
      """A ClassDef with dynamic attributes."""
  
      DYNAMIC_CLASS_DEF = True
  
      def __init__(self, class_, alias=None, static_attrs=None, amf3=True,
          encode_types=None, decode_types=None, include_private=None, _built_in=False):
          ClassDef.__init__(self, class_, alias, static_attrs, amf3,
              encode_types, decode_types, _built_in)
  
          self.include_private = include_private
  
      def getDynamicAttrVals(self, obj, include_private=False):
          """Returns a dict where keys are attribute names and values are attribute values.
  
          arguments
          ==========
          obj - object, the object to get attributes for.
          include_private - bool, if False do not include attributes with
              names starting with '_'. Default = False.
          """
          if self.include_private is None:
              ip = include_private
          else:
              ip = self.include_private
  
          return get_dynamic_attr_vals(obj, self.static_attrs, ip);
  
  class ExternClassDef(ClassDef):
      """A ClassDef where the byte string encoding/decoding is customized.
     
      The Actionscript version of the class must implement IExternalizeable.
      """
      
      EXTERNALIZABLE_CLASS_DEF = True
      
      def __init__(self, class_, alias=None, static_attrs=None, _built_in=False):
          ClassDef.__init__(self, class_, alias, static_attrs, amf3=True,
              _built_in=_built_in)
   
      def writeExternal(self, obj, context):
          """
          This method must be overridden in a sub-class.
  
          arguments
          ==========
           * obj - object, The object that is being encoded.
           * context - amfast.decoder.EncoderContext, holds encoding related properties.
          """
          raise ClassDefError("This method must be implemented by a sub-class.")
  
      def readExternal(self, obj, context):
          """
          This method must be overridden in a sub-class.
  
          arguments
          ==========
           * obj - object, The object that the byte string is being applied to.
           * context - amfast.decoder.DecoderContext, holds decoding related properties.
          """
          raise ClassDefError("This method must be implemented by a sub-class.")
  
  class _ProxyClassDef(ExternClassDef):
      """A special class used internally to encode/decode Proxied objects."""
  
      PROXY_CLASS_DEF = True
      PROXY_ALIAS = 'proxy'
  
      class _ProxyObject(object):
          """Empty class used for mapping."""
          pass
  
      def __init__(self):
          ExternClassDef.__init__(self, self._ProxyObject, self.PROXY_ALIAS,
              None, _built_in=True)
  
  class _ArrayCollectionClassDef(_ProxyClassDef):
      """A special ClassDef used internally to encode/decode an ArrayCollection."""
  
      ARRAY_COLLECTION_CLASS_DEF = True
      PROXY_ALIAS = 'flex.messaging.io.ArrayCollection'
  
      def __init__(self):
          _ProxyClassDef.__init__(self)
  
  class _ObjectProxyClassDef(_ProxyClassDef):
      """A special ClassDef used internally to encode/decode an ObjectProxy."""
  
      OBJECT_PROXY_CLASS_DEF = True
      PROXY_ALIAS = 'flex.messaging.io.ObjectProxy'
  
      def __init__(self):
          _ProxyClassDef.__init__(self)
  
  class ClassDefMapper(object):
      """Map classes to ClassDefs, retrieve class_defs by class or alias name."""
      def __init__(self):
          """
          arguments
          ==========
          * class_def_attr - string, an attribute with this name will be added
              mapped classes. Default = '_amf_alias'
          """
  
          self._lock = threading.RLock()
          self._mapped_classes = {}
          self._mapped_aliases = {}
          self._mapBuiltIns()
  
      def __iter__(self):
          return self._mapped_aliases.itervalues()
  
      def _mapBuiltIns(self):
          """Map built-in ClassDefs for default behavior."""
          from as_types import AsError
          from amfast.remoting import flex_messages as messaging
  
          # Proxy objects
          self.mapClass(_ArrayCollectionClassDef())
          self.mapClass(_ObjectProxyClassDef())
  
          # Exceptions
          self.mapClass(ClassDef(AsError, _built_in=True))
          self.mapClass(ClassDef(messaging.FaultError, _built_in=True))
  
          # Flex remoting messages
          self.mapClass(ClassDef(messaging.RemotingMessage, _built_in=True))
          self.mapClass(messaging.AsyncSmallMsgDef(messaging.AsyncMessage,
              alias="DSA", _built_in=True))
          self.mapClass(ClassDef(messaging.AsyncMessage, _built_in=True))
          self.mapClass(messaging.CommandSmallMsgDef(messaging.CommandMessage,
              alias="DSC", _built_in=True))
          self.mapClass(ClassDef(messaging.CommandMessage, _built_in=True))
          self.mapClass(ClassDef(messaging.AcknowledgeMessage, _built_in=True))
          self.mapClass(ClassDef(messaging.ErrorMessage, _built_in=True))
  
      def mapClass(self, class_def):
          """Map a class_def implementation, so that it can be retrieved based on class attributes.
  
          arguments
          ==========
           * class_def - ClassDef, ClassDef being mapped.
          """
          if not hasattr(class_def, 'CLASS_DEF'):
              raise ClassDefError("class_def argument must be a ClassDef object.")
  
          self._lock.acquire()
          try:
              self._mapped_classes[class_def.class_] = class_def
              self._mapped_aliases[class_def.alias] = class_def
          finally:
              self._lock.release()
  
      def getClassDefByClass(self, class_):
          """Get a ClassDef.
  
          Returns None if ClassDef is not found.
  
          arguments
          ==========
           * class_ - class, the class to find a ClassDef for.
          """
          return self._mapped_classes.get(class_, None)
  
      def getClassDefByAlias(self, alias):
          """Get a ClassDef.
  
          Returns None in not ClassDef is found.
  
          arguments
          ==========
           * alias - string, the alias to find a ClassDef for.
          """
          return self._mapped_aliases.get(alias, None)
  
      def unmapClass(self, class_):
          """Unmap a class definition.
  
          arguments
          ==========
           * class_ - class, the class to remove a ClassDef for.
          """
          self._lock.acquire()
          try:
              for alias, klass in self._mapped_aliases.iteritems():
                  if class_ == klass:
                      del self._mapped_aliases[alias]
  
              class_id = id(class_)
              if class_id in self._mapped_classes:
                  del self._mapped_classes[class_id]
          finally:
              self._lock.release()
  
  # ---- module attributes ---- #
  
  def get_dynamic_attr_vals(obj, ignore_attrs=None, include_private=False):
      """Returns a dict of attribute values to encode.
  
      keys = attribute names, values = attribute values.
  
      argmuents
      ==========
       * obj - object, object to get dynamic attribute values from.
       * ignore_attrs - list or tuple of attributes to ignore. Default = empty tuple.
       * include_private - bool, if False do not include attributes that start with '_'.
            Default = False.
      """ 
      vals = {}
  
      if hasattr(obj, '__dict__'):
          for attr, val in obj.__dict__.iteritems():
              if ignore_attrs is not None:
                  if attr in ignore_attrs:
                      continue
  
              if (include_private is False) and (attr.startswith('_')):
                  continue
  
              vals[attr] = val
  
      return vals
  
  # These properties can be set on a class
  # to map attributes within the class.
  ALIAS = '_AMFAST_ALIAS'
  STATIC_ATTRS = '_AMFAST_STATIC_ATTRS'
  AMF3 = '_AMFAST_AMF3'
  
  def assign_attrs(class_, alias=None, static_attrs=None, amf3=None):
      """
      Use to map ClassDef attributes to a class. Useful if you want to keep
      ClassDef configuration with the class being mapped, instead of at 
      the point where the ClassDef is created.
  
      If you assign ClassDef attributes with this method, you can
      call ClassDef(class_) to create a ClassDef, and the assigned
      attributes will be applied to the new ClassDef.
  
      Arguments provided to the ClassDef() will override attributes
      that were assigned with this function.
  
      arguments
      ==========
       * class_ - class, the class to assign attributes to.
       * alias - string, the amf alias name of the mapped class
       * static_attrs - tuple, a tuple of static attribute names, all values must be strings or unicode
       * amf3 - bool, if True, this object will be encoded in AMF3.
      """
      if alias is not None:
          setattr(class_, ALIAS, alias)
  
      if static_attrs is not None:
          setattr(class_, STATIC_ATTRS, static_attrs)
  
      if amf3 is not None:
          setattr(class_, AMF3, amf3)
  