diff --git a/coolamqp/framing/__init__.py b/coolamqp/framing/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f2b35b38d89264ee25685611d0a65a192e165f6
--- /dev/null
+++ b/coolamqp/framing/__init__.py
@@ -0,0 +1,2 @@
+# coding=UTF-8
+from __future__ import absolute_import, division, print_function
diff --git a/coolamqp/framing/definitions.py b/coolamqp/framing/definitions.py
new file mode 100644
index 0000000000000000000000000000000000000000..921c176dd1371100cb57675772c4585383cdeb23
--- /dev/null
+++ b/coolamqp/framing/definitions.py
@@ -0,0 +1,2589 @@
+# coding=UTF-8
+from __future__ import print_function, absolute_import
+"""
+Constants used in AMQP protocol.
+
+Generated automatically by CoolAMQP from AMQP machine-readable specification.
+See utils/compdefs.py for the tool
+
+AMQP is copyright (c) 2016 OASIS
+CoolAMQP is copyright (c) 2016 DMS Serwis s.c.
+"""
+
+# Core frame types
+FRAME_METHOD = 1
+FRAME_HEADER = 2
+FRAME_BODY = 3
+FRAME_HEARTBEAT = 8
+FRAME_MIN_SIZE = 4096
+FRAME_END = 206
+REPLY_SUCCESS = 200 # Indicates that the method completed successfully. This reply code is
+                    # reserved for future use - the current protocol design does not use positive
+                    # confirmation and reply codes are sent only in case of an error.
+CONTENT_TOO_LARGE = 311 # The client attempted to transfer content larger than the server could accept
+                        # at the present time. The client may retry at a later time.
+NO_CONSUMERS = 313 # When the exchange cannot deliver to a consumer when the immediate flag is
+                   # set. As a result of pending data on the queue or the absence of any
+                   # consumers of the queue.
+CONNECTION_FORCED = 320 # An operator intervened to close the connection for some reason. The client
+                        # may retry at some later date.
+INVALID_PATH = 402 # The client tried to work with an unknown virtual host.
+ACCESS_REFUSED = 403 # The client attempted to work with a server entity to which it has no
+                     # access due to security settings.
+NOT_FOUND = 404 # The client attempted to work with a server entity that does not exist.
+RESOURCE_LOCKED = 405 # The client attempted to work with a server entity to which it has no
+                      # access because another client is working with it.
+PRECONDITION_FAILED = 406 # The client requested a method that was not allowed because some precondition
+                          # failed.
+FRAME_ERROR = 501 # The sender sent a malformed frame that the recipient could not decode.
+                  # This strongly implies a programming error in the sending peer.
+SYNTAX_ERROR = 502 # The sender sent a frame that contained illegal values for one or more
+                   # fields. This strongly implies a programming error in the sending peer.
+COMMAND_INVALID = 503 # The client sent an invalid sequence of frames, attempting to perform an
+                      # operation that was considered invalid by the server. This usually implies
+                      # a programming error in the client.
+CHANNEL_ERROR = 504 # The client attempted to work with a channel that had not been correctly
+                    # opened. This most likely indicates a fault in the client layer.
+UNEXPECTED_FRAME = 505 # The peer sent a frame that was not expected, usually in the context of
+                       # a content header and body.  This strongly indicates a fault in the peer's
+                       # content processing.
+RESOURCE_ERROR = 506 # The server could not complete the method because it lacked sufficient
+                     # resources. This may be due to the client creating too many of some type
+                     # of entity.
+NOT_ALLOWED = 530 # The client tried to work with some entity in a manner that is prohibited
+                  # by the server, due to security settings or by some other criteria.
+NOT_IMPLEMENTED = 540 # The client tried to use functionality that is not implemented in the
+                      # server.
+INTERNAL_ERROR = 541 # The server could not complete the method because of an internal error.
+                     # The server may require intervention by an operator in order to resume
+                     # normal operations.
+DOMAIN_TO_BASIC_TYPE = {
+    u'class-id': u'short',
+    u'consumer-tag': u'shortstr',
+    u'delivery-tag': u'longlong',
+    u'exchange-name': u'shortstr',
+    u'method-id': u'short',
+    u'no-ack': u'bit',
+    u'no-local': u'bit',
+    u'no-wait': u'bit',
+    u'path': u'shortstr',
+    u'peer-properties': u'table',
+    u'queue-name': u'shortstr',
+    u'redelivered': u'bit',
+    u'message-count': u'long',
+    u'reply-code': u'short',
+    u'reply-text': u'shortstr',
+    u'bit': None,
+    u'octet': None,
+    u'short': None,
+    u'long': None,
+    u'longlong': None,
+    u'shortstr': None,
+    u'longstr': None,
+    u'timestamp': None,
+    u'table': None,
+}
+
+
+class AMQPClass(object):
+    pass
+
+
+class AMQPMethod(object):
+    RESPONSE_TO = None
+    REPLY_WITH = []
+
+
+class Connection(AMQPClass):
+    """
+    The connection class provides methods for a client to establish a network connection to
+    
+    a server, and for both peers to operate the connection thereafter.
+    """
+    NAME = u'connection'
+    INDEX = 10
+
+
+class ConnectionClose(AMQPMethod):
+    """
+    Request a connection close
+    
+    This method indicates that the sender wants to close the connection. This may be
+    due to internal conditions (e.g. a forced shut-down) or due to an error handling
+    a specific method, i.e. an exception. When a close is due to an exception, the
+    sender provides the class and method id of the method which caused the exception.
+    """
+    CLASS = Connection
+    NAME = u'close'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 50
+    FULLNAME = u'connection.close'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ConnectionCloseOk]
+    FIELDS = [
+        (u'reply-code', u'reply-code', u'short'), 
+        (u'reply-text', u'reply-text', u'shortstr'), 
+        (u'class-id', u'class-id', u'short'),  # failing method class
+        (u'method-id', u'method-id', u'short'),  # failing method ID
+    ]
+
+    def __init__(self, reply_code, reply_text, class_id, method_id):
+        """
+        Create frame connection.close
+
+        :type reply_code: reply-code (as short)
+        :type reply_text: reply-text (as shortstr)
+        :param class_id: Failing method class
+            When the close is provoked by a method exception, this is the class of the
+            method.
+        :type class_id: class-id (as short)
+        :param method_id: Failing method id
+            When the close is provoked by a method exception, this is the ID of the method.
+        :type method_id: method-id (as short)
+        """
+        self.reply_code = reply_code
+        self.reply_text = reply_text
+        self.class_id = class_id
+        self.method_id = method_id
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ConnectionCloseOk(AMQPMethod):
+    """
+    Confirm a connection close
+    
+    This method confirms a Connection.Close method and tells the recipient that it is
+    safe to release resources for the connection and close the socket.
+    """
+    CLASS = Connection
+    NAME = u'close-ok'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 51
+    FULLNAME = u'connection.close-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = ConnectionClose
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame connection.close-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ConnectionOpen(AMQPMethod):
+    """
+    Open connection to virtual host
+    
+    This method opens a connection to a virtual host, which is a collection of
+    resources, and acts to separate multiple application domains within a server.
+    The server may apply arbitrary limits per virtual host, such as the number
+    of each type of entity that may be used, per connection and/or in total.
+    """
+    CLASS = Connection
+    NAME = u'open'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 40
+    FULLNAME = u'connection.open'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ConnectionOpenOk]
+    FIELDS = [
+        (u'virtual-host', u'path', u'shortstr'),  # virtual host name
+        (u'reserved-1', u'shortstr', u'shortstr'), 
+        (u'reserved-2', u'bit', u'bit'), 
+    ]
+
+    def __init__(self, virtual_host):
+        """
+        Create frame connection.open
+
+        :param virtual_host: Virtual host name
+            The name of the virtual host to work with.
+        :type virtual_host: path (as shortstr)
+        """
+        self.virtual_host = virtual_host
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ConnectionOpenOk(AMQPMethod):
+    """
+    Signal that connection is ready
+    
+    This method signals to the client that the connection is ready for use.
+    """
+    CLASS = Connection
+    NAME = u'open-ok'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 41
+    FULLNAME = u'connection.open-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = ConnectionOpen
+    FIELDS = [
+        (u'reserved-1', u'shortstr', u'shortstr'), 
+    ]
+
+    def __init__(self):
+        """
+        Create frame connection.open-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ConnectionStart(AMQPMethod):
+    """
+    Start connection negotiation
+    
+    This method starts the connection negotiation process by telling the client the
+    protocol version that the server proposes, along with a list of security mechanisms
+    which the client can use for authentication.
+    """
+    CLASS = Connection
+    NAME = u'start'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 10
+    FULLNAME = u'connection.start'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ConnectionStartOk]
+    FIELDS = [
+        (u'version-major', u'octet', u'octet'),  # protocol major version
+        (u'version-minor', u'octet', u'octet'),  # protocol minor version
+        (u'server-properties', u'peer-properties', u'table'),  # server properties
+        (u'mechanisms', u'longstr', u'longstr'),  # available security mechanisms
+        (u'locales', u'longstr', u'longstr'),  # available message locales
+    ]
+
+    def __init__(self, version_major, version_minor, server_properties, mechanisms, locales):
+        """
+        Create frame connection.start
+
+        :param version_major: Protocol major version
+            The major version number can take any value from 0 to 99 as defined in the
+            AMQP specification.
+        :type version_major: octet (as octet)
+        :param version_minor: Protocol minor version
+            The minor version number can take any value from 0 to 99 as defined in the
+            AMQP specification.
+        :type version_minor: octet (as octet)
+        :param server_properties: Server properties
+            The properties SHOULD contain at least these fields: "host", specifying the
+            server host name or address, "product", giving the name of the server product,
+            "version", giving the name of the server version, "platform", giving the name
+            of the operating system, "copyright", if appropriate, and "information", giving
+            other general information.
+        :type server_properties: peer-properties (as table)
+        :param mechanisms: Available security mechanisms
+            A list of the security mechanisms that the server supports, delimited by spaces.
+        :type mechanisms: longstr (as longstr)
+        :param locales: Available message locales
+            A list of the message locales that the server supports, delimited by spaces. The
+            locale defines the language in which the server will send reply texts.
+        :type locales: longstr (as longstr)
+        """
+        self.version_major = version_major
+        self.version_minor = version_minor
+        self.server_properties = server_properties
+        self.mechanisms = mechanisms
+        self.locales = locales
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ConnectionSecure(AMQPMethod):
+    """
+    Security mechanism challenge
+    
+    The SASL protocol works by exchanging challenges and responses until both peers have
+    received sufficient information to authenticate each other. This method challenges
+    the client to provide more information.
+    """
+    CLASS = Connection
+    NAME = u'secure'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 20
+    FULLNAME = u'connection.secure'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ConnectionSecureOk]
+    FIELDS = [
+        (u'challenge', u'longstr', u'longstr'),  # security challenge data
+    ]
+
+    def __init__(self, challenge):
+        """
+        Create frame connection.secure
+
+        :param challenge: Security challenge data
+            Challenge information, a block of opaque binary data passed to the security
+            mechanism.
+        :type challenge: longstr (as longstr)
+        """
+        self.challenge = challenge
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ConnectionStartOk(AMQPMethod):
+    """
+    Select security mechanism and locale
+    
+    This method selects a SASL security mechanism.
+    """
+    CLASS = Connection
+    NAME = u'start-ok'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 11
+    FULLNAME = u'connection.start-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = ConnectionStart
+    FIELDS = [
+        (u'client-properties', u'peer-properties', u'table'),  # client properties
+        (u'mechanism', u'shortstr', u'shortstr'),  # selected security mechanism
+        (u'response', u'longstr', u'longstr'),  # security response data
+        (u'locale', u'shortstr', u'shortstr'),  # selected message locale
+    ]
+
+    def __init__(self, client_properties, mechanism, response, locale):
+        """
+        Create frame connection.start-ok
+
+        :param client_properties: Client properties
+            The properties SHOULD contain at least these fields: "product", giving the name
+            of the client product, "version", giving the name of the client version, "platform",
+            giving the name of the operating system, "copyright", if appropriate, and
+            "information", giving other general information.
+        :type client_properties: peer-properties (as table)
+        :param mechanism: Selected security mechanism
+            A single security mechanisms selected by the client, which must be one of those
+            specified by the server.
+        :type mechanism: shortstr (as shortstr)
+        :param response: Security response data
+            A block of opaque data passed to the security mechanism. The contents of this
+            data are defined by the SASL security mechanism.
+        :type response: longstr (as longstr)
+        :param locale: Selected message locale
+            A single message locale selected by the client, which must be one of those
+            specified by the server.
+        :type locale: shortstr (as shortstr)
+        """
+        self.client_properties = client_properties
+        self.mechanism = mechanism
+        self.response = response
+        self.locale = locale
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ConnectionSecureOk(AMQPMethod):
+    """
+    Security mechanism response
+    
+    This method attempts to authenticate, passing a block of SASL data for the security
+    mechanism at the server side.
+    """
+    CLASS = Connection
+    NAME = u'secure-ok'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 21
+    FULLNAME = u'connection.secure-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = ConnectionSecure
+    FIELDS = [
+        (u'response', u'longstr', u'longstr'),  # security response data
+    ]
+
+    def __init__(self, response):
+        """
+        Create frame connection.secure-ok
+
+        :param response: Security response data
+            A block of opaque data passed to the security mechanism. The contents of this
+            data are defined by the SASL security mechanism.
+        :type response: longstr (as longstr)
+        """
+        self.response = response
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ConnectionTune(AMQPMethod):
+    """
+    Propose connection tuning parameters
+    
+    This method proposes a set of connection configuration values to the client. The
+    client can accept and/or adjust these.
+    """
+    CLASS = Connection
+    NAME = u'tune'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 30
+    FULLNAME = u'connection.tune'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ConnectionTuneOk]
+    FIELDS = [
+        (u'channel-max', u'short', u'short'),  # proposed maximum channels
+        (u'frame-max', u'long', u'long'),  # proposed maximum frame size
+        (u'heartbeat', u'short', u'short'),  # desired heartbeat delay
+    ]
+
+    def __init__(self, channel_max, frame_max, heartbeat):
+        """
+        Create frame connection.tune
+
+        :param channel_max: Proposed maximum channels
+            Specifies highest channel number that the server permits.  Usable channel numbers
+            are in the range 1..channel-max.  Zero indicates no specified limit.
+        :type channel_max: short (as short)
+        :param frame_max: Proposed maximum frame size
+            The largest frame size that the server proposes for the connection, including
+            frame header and end-byte.  The client can negotiate a lower value. Zero means
+            that the server does not impose any specific limit but may reject very large
+            frames if it cannot allocate resources for them.
+        :type frame_max: long (as long)
+        :param heartbeat: Desired heartbeat delay
+            The delay, in seconds, of the connection heartbeat that the server wants.
+            Zero means the server does not want a heartbeat.
+        :type heartbeat: short (as short)
+        """
+        self.channel_max = channel_max
+        self.frame_max = frame_max
+        self.heartbeat = heartbeat
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ConnectionTuneOk(AMQPMethod):
+    """
+    Negotiate connection tuning parameters
+    
+    This method sends the client's connection tuning parameters to the server.
+    Certain fields are negotiated, others provide capability information.
+    """
+    CLASS = Connection
+    NAME = u'tune-ok'
+    CLASSNAME = u'connection'
+    CLASS_INDEX = 10
+    METHOD_INDEX = 31
+    FULLNAME = u'connection.tune-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = ConnectionTune
+    FIELDS = [
+        (u'channel-max', u'short', u'short'),  # negotiated maximum channels
+        (u'frame-max', u'long', u'long'),  # negotiated maximum frame size
+        (u'heartbeat', u'short', u'short'),  # desired heartbeat delay
+    ]
+
+    def __init__(self, channel_max, frame_max, heartbeat):
+        """
+        Create frame connection.tune-ok
+
+        :param channel_max: Negotiated maximum channels
+            The maximum total number of channels that the client will use per connection.
+        :type channel_max: short (as short)
+        :param frame_max: Negotiated maximum frame size
+            The largest frame size that the client and server will use for the connection.
+            Zero means that the client does not impose any specific limit but may reject
+            very large frames if it cannot allocate resources for them. Note that the
+            frame-max limit applies principally to content frames, where large contents can
+            be broken into frames of arbitrary size.
+        :type frame_max: long (as long)
+        :param heartbeat: Desired heartbeat delay
+            The delay, in seconds, of the connection heartbeat that the client wants. Zero
+            means the client does not want a heartbeat.
+        :type heartbeat: short (as short)
+        """
+        self.channel_max = channel_max
+        self.frame_max = frame_max
+        self.heartbeat = heartbeat
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+class Channel(AMQPClass):
+    """
+    The channel class provides methods for a client to establish a channel to a
+    
+    server and for both peers to operate the channel thereafter.
+    """
+    NAME = u'channel'
+    INDEX = 20
+
+
+class ChannelClose(AMQPMethod):
+    """
+    Request a channel close
+    
+    This method indicates that the sender wants to close the channel. This may be due to
+    internal conditions (e.g. a forced shut-down) or due to an error handling a specific
+    method, i.e. an exception. When a close is due to an exception, the sender provides
+    the class and method id of the method which caused the exception.
+    """
+    CLASS = Channel
+    NAME = u'close'
+    CLASSNAME = u'channel'
+    CLASS_INDEX = 20
+    METHOD_INDEX = 40
+    FULLNAME = u'channel.close'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ChannelCloseOk]
+    FIELDS = [
+        (u'reply-code', u'reply-code', u'short'), 
+        (u'reply-text', u'reply-text', u'shortstr'), 
+        (u'class-id', u'class-id', u'short'),  # failing method class
+        (u'method-id', u'method-id', u'short'),  # failing method ID
+    ]
+
+    def __init__(self, reply_code, reply_text, class_id, method_id):
+        """
+        Create frame channel.close
+
+        :type reply_code: reply-code (as short)
+        :type reply_text: reply-text (as shortstr)
+        :param class_id: Failing method class
+            When the close is provoked by a method exception, this is the class of the
+            method.
+        :type class_id: class-id (as short)
+        :param method_id: Failing method id
+            When the close is provoked by a method exception, this is the ID of the method.
+        :type method_id: method-id (as short)
+        """
+        self.reply_code = reply_code
+        self.reply_text = reply_text
+        self.class_id = class_id
+        self.method_id = method_id
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ChannelCloseOk(AMQPMethod):
+    """
+    Confirm a channel close
+    
+    This method confirms a Channel.Close method and tells the recipient that it is safe
+    to release resources for the channel.
+    """
+    CLASS = Channel
+    NAME = u'close-ok'
+    CLASSNAME = u'channel'
+    CLASS_INDEX = 20
+    METHOD_INDEX = 41
+    FULLNAME = u'channel.close-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = ChannelClose
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame channel.close-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ChannelFlow(AMQPMethod):
+    """
+    Enable/disable flow from peer
+    
+    This method asks the peer to pause or restart the flow of content data sent by
+    a consumer. This is a simple flow-control mechanism that a peer can use to avoid
+    overflowing its queues or otherwise finding itself receiving more messages than
+    it can process. Note that this method is not intended for window control. It does
+    not affect contents returned by Basic.Get-Ok methods.
+    """
+    CLASS = Channel
+    NAME = u'flow'
+    CLASSNAME = u'channel'
+    CLASS_INDEX = 20
+    METHOD_INDEX = 20
+    FULLNAME = u'channel.flow'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ChannelFlowOk]
+    FIELDS = [
+        (u'active', u'bit', u'bit'),  # start/stop content frames
+    ]
+
+    def __init__(self, active):
+        """
+        Create frame channel.flow
+
+        :param active: Start/stop content frames
+            If 1, the peer starts sending content frames. If 0, the peer stops sending
+            content frames.
+        :type active: bit (as bit)
+        """
+        self.active = active
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ChannelFlowOk(AMQPMethod):
+    """
+    Confirm a flow method
+    
+    Confirms to the peer that a flow command was received and processed.
+    """
+    CLASS = Channel
+    NAME = u'flow-ok'
+    CLASSNAME = u'channel'
+    CLASS_INDEX = 20
+    METHOD_INDEX = 21
+    FULLNAME = u'channel.flow-ok'
+    SYNCHRONOUS = False
+    REPLY_WITH = []
+    RESPONSE_TO = ChannelFlow
+    FIELDS = [
+        (u'active', u'bit', u'bit'),  # current flow setting
+    ]
+
+    def __init__(self, active):
+        """
+        Create frame channel.flow-ok
+
+        :param active: Current flow setting
+            Confirms the setting of the processed flow method: 1 means the peer will start
+            sending or continue to send content frames; 0 means it will not.
+        :type active: bit (as bit)
+        """
+        self.active = active
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ChannelOpen(AMQPMethod):
+    """
+    Open a channel for use
+    
+    This method opens a channel to the server.
+    """
+    CLASS = Channel
+    NAME = u'open'
+    CLASSNAME = u'channel'
+    CLASS_INDEX = 20
+    METHOD_INDEX = 10
+    FULLNAME = u'channel.open'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ChannelOpenOk]
+    FIELDS = [
+        (u'reserved-1', u'shortstr', u'shortstr'), 
+    ]
+
+    def __init__(self):
+        """
+        Create frame channel.open
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ChannelOpenOk(AMQPMethod):
+    """
+    Signal that the channel is ready
+    
+    This method signals to the client that the channel is ready for use.
+    """
+    CLASS = Channel
+    NAME = u'open-ok'
+    CLASSNAME = u'channel'
+    CLASS_INDEX = 20
+    METHOD_INDEX = 11
+    FULLNAME = u'channel.open-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = ChannelOpen
+    FIELDS = [
+        (u'reserved-1', u'longstr', u'longstr'), 
+    ]
+
+    def __init__(self):
+        """
+        Create frame channel.open-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+class Exchange(AMQPClass):
+    """
+    Exchanges match and distribute messages across queues. exchanges can be configured in
+    
+    the server or declared at runtime.
+    """
+    NAME = u'exchange'
+    INDEX = 40
+
+
+class ExchangeDeclare(AMQPMethod):
+    """
+    Verify exchange exists, create if needed
+    
+    This method creates an exchange if it does not already exist, and if the exchange
+    exists, verifies that it is of the correct and expected class.
+    """
+    CLASS = Exchange
+    NAME = u'declare'
+    CLASSNAME = u'exchange'
+    CLASS_INDEX = 40
+    METHOD_INDEX = 10
+    FULLNAME = u'exchange.declare'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ExchangeDeclareOk]
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'exchange', u'exchange-name', u'shortstr'), 
+        (u'type', u'shortstr', u'shortstr'),  # exchange type
+        (u'passive', u'bit', u'bit'),  # do not create exchange
+        (u'durable', u'bit', u'bit'),  # request a durable exchange
+        (u'reserved-2', u'bit', u'bit'), 
+        (u'reserved-3', u'bit', u'bit'), 
+        (u'no-wait', u'no-wait', u'bit'), 
+        (u'arguments', u'table', u'table'),  # arguments for declaration
+    ]
+
+    def __init__(self, exchange, type, passive, durable, no_wait, arguments):
+        """
+        Create frame exchange.declare
+
+        :param exchange: Exchange names starting with "amq." are reserved for pre-declared and
+            standardised exchanges. The client MAY declare an exchange starting with
+            "amq." if the passive option is set, or the exchange already exists.
+        :type exchange: exchange-name (as shortstr)
+        :param type: Exchange type
+            Each exchange belongs to one of a set of exchange types implemented by the
+            server. The exchange types define the functionality of the exchange - i.e. how
+            messages are routed through it. It is not valid or meaningful to attempt to
+            change the type of an existing exchange.
+        :type type: shortstr (as shortstr)
+        :param passive: Do not create exchange
+            If set, the server will reply with Declare-Ok if the exchange already
+            exists with the same name, and raise an error if not.  The client can
+            use this to check whether an exchange exists without modifying the
+            server state. When set, all other method fields except name and no-wait
+            are ignored.  A declare with both passive and no-wait has no effect.
+            Arguments are compared for semantic equivalence.
+        :type passive: bit (as bit)
+        :param durable: Request a durable exchange
+            If set when creating a new exchange, the exchange will be marked as durable.
+            Durable exchanges remain active when a server restarts. Non-durable exchanges
+            (transient exchanges) are purged if/when a server restarts.
+        :type durable: bit (as bit)
+        :type no_wait: no-wait (as bit)
+        :param arguments: Arguments for declaration
+            A set of arguments for the declaration. The syntax and semantics of these
+            arguments depends on the server implementation.
+        :type arguments: table (as table)
+        """
+        self.exchange = exchange
+        self.type = type
+        self.passive = passive
+        self.durable = durable
+        self.no_wait = no_wait
+        self.arguments = arguments
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ExchangeDelete(AMQPMethod):
+    """
+    Delete an exchange
+    
+    This method deletes an exchange. When an exchange is deleted all queue bindings on
+    the exchange are cancelled.
+    """
+    CLASS = Exchange
+    NAME = u'delete'
+    CLASSNAME = u'exchange'
+    CLASS_INDEX = 40
+    METHOD_INDEX = 20
+    FULLNAME = u'exchange.delete'
+    SYNCHRONOUS = True
+    REPLY_WITH = [ExchangeDeleteOk]
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'exchange', u'exchange-name', u'shortstr'), 
+        (u'if-unused', u'bit', u'bit'),  # delete only if unused
+        (u'no-wait', u'no-wait', u'bit'), 
+    ]
+
+    def __init__(self, exchange, if_unused, no_wait):
+        """
+        Create frame exchange.delete
+
+        :param exchange:             The client must not attempt to delete an exchange that does not exist.
+
+        :type exchange: exchange-name (as shortstr)
+        :param if_unused: Delete only if unused
+            If set, the server will only delete the exchange if it has no queue bindings. If
+            the exchange has queue bindings the server does not delete it but raises a
+            channel exception instead.
+        :type if_unused: bit (as bit)
+        :type no_wait: no-wait (as bit)
+        """
+        self.exchange = exchange
+        self.if_unused = if_unused
+        self.no_wait = no_wait
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ExchangeDeclareOk(AMQPMethod):
+    """
+    Confirm exchange declaration
+    
+    This method confirms a Declare method and confirms the name of the exchange,
+    essential for automatically-named exchanges.
+    """
+    CLASS = Exchange
+    NAME = u'declare-ok'
+    CLASSNAME = u'exchange'
+    CLASS_INDEX = 40
+    METHOD_INDEX = 11
+    FULLNAME = u'exchange.declare-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = ExchangeDeclare
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame exchange.declare-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class ExchangeDeleteOk(AMQPMethod):
+    """
+    Confirm deletion of an exchange
+    
+    This method confirms the deletion of an exchange.
+    """
+    CLASS = Exchange
+    NAME = u'delete-ok'
+    CLASSNAME = u'exchange'
+    CLASS_INDEX = 40
+    METHOD_INDEX = 21
+    FULLNAME = u'exchange.delete-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = ExchangeDelete
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame exchange.delete-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+class Queue(AMQPClass):
+    """
+    Queues store and forward messages. queues can be configured in the server or created at
+    
+    runtime. Queues must be attached to at least one exchange in order to receive messages
+    from publishers.
+    """
+    NAME = u'queue'
+    INDEX = 50
+
+
+class QueueBind(AMQPMethod):
+    """
+    Bind queue to an exchange
+    
+    This method binds a queue to an exchange. Until a queue is bound it will not
+    receive any messages. In a classic messaging model, store-and-forward queues
+    are bound to a direct exchange and subscription queues are bound to a topic
+    exchange.
+    """
+    CLASS = Queue
+    NAME = u'bind'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 20
+    FULLNAME = u'queue.bind'
+    SYNCHRONOUS = True
+    REPLY_WITH = [QueueBindOk]
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'queue', u'queue-name', u'shortstr'), 
+        (u'exchange', u'exchange-name', u'shortstr'),  # name of the exchange to bind to
+        (u'routing-key', u'shortstr', u'shortstr'),  # message routing key
+        (u'no-wait', u'no-wait', u'bit'), 
+        (u'arguments', u'table', u'table'),  # arguments for binding
+    ]
+
+    def __init__(self, queue, exchange, routing_key, no_wait, arguments):
+        """
+        Create frame queue.bind
+
+        :param queue:             Specifies the name of the queue to bind.
+
+        :type queue: queue-name (as shortstr)
+        :param exchange: Name of the exchange to bind to
+            A client MUST NOT be allowed to bind a queue to a non-existent exchange.
+        :type exchange: exchange-name (as shortstr)
+        :param routing_key: Message routing key
+            Specifies the routing key for the binding. The routing key is used for routing
+            messages depending on the exchange configuration. Not all exchanges use a
+            routing key - refer to the specific exchange documentation.  If the queue name
+            is empty, the server uses the last queue declared on the channel.  If the
+            routing key is also empty, the server uses this queue name for the routing
+            key as well.  If the queue name is provided but the routing key is empty, the
+            server does the binding with that empty routing key.  The meaning of empty
+            routing keys depends on the exchange implementation.
+        :type routing_key: shortstr (as shortstr)
+        :type no_wait: no-wait (as bit)
+        :param arguments: Arguments for binding
+            A set of arguments for the binding. The syntax and semantics of these arguments
+            depends on the exchange class.
+        :type arguments: table (as table)
+        """
+        self.queue = queue
+        self.exchange = exchange
+        self.routing_key = routing_key
+        self.no_wait = no_wait
+        self.arguments = arguments
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class QueueBindOk(AMQPMethod):
+    """
+    Confirm bind successful
+    
+    This method confirms that the bind was successful.
+    """
+    CLASS = Queue
+    NAME = u'bind-ok'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 21
+    FULLNAME = u'queue.bind-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = QueueBind
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame queue.bind-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class QueueDeclare(AMQPMethod):
+    """
+    Declare queue, create if needed
+    
+    This method creates or checks a queue. When creating a new queue the client can
+    specify various properties that control the durability of the queue and its
+    contents, and the level of sharing for the queue.
+    """
+    CLASS = Queue
+    NAME = u'declare'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 10
+    FULLNAME = u'queue.declare'
+    SYNCHRONOUS = True
+    REPLY_WITH = [QueueDeclareOk]
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'queue', u'queue-name', u'shortstr'), 
+        (u'passive', u'bit', u'bit'),  # do not create queue
+        (u'durable', u'bit', u'bit'),  # request a durable queue
+        (u'exclusive', u'bit', u'bit'),  # request an exclusive queue
+        (u'auto-delete', u'bit', u'bit'),  # auto-delete queue when unused
+        (u'no-wait', u'no-wait', u'bit'), 
+        (u'arguments', u'table', u'table'),  # arguments for declaration
+    ]
+
+    def __init__(self, queue, passive, durable, exclusive, auto_delete, no_wait, arguments):
+        """
+        Create frame queue.declare
+
+        :param queue: The queue name may be empty, in which case the server must create a new
+            queue with a unique generated name and return this to the client in the
+            Declare-Ok method.
+        :type queue: queue-name (as shortstr)
+        :param passive: Do not create queue
+            If set, the server will reply with Declare-Ok if the queue already
+            exists with the same name, and raise an error if not.  The client can
+            use this to check whether a queue exists without modifying the
+            server state.  When set, all other method fields except name and no-wait
+            are ignored.  A declare with both passive and no-wait has no effect.
+            Arguments are compared for semantic equivalence.
+        :type passive: bit (as bit)
+        :param durable: Request a durable queue
+            If set when creating a new queue, the queue will be marked as durable. Durable
+            queues remain active when a server restarts. Non-durable queues (transient
+            queues) are purged if/when a server restarts. Note that durable queues do not
+            necessarily hold persistent messages, although it does not make sense to send
+            persistent messages to a transient queue.
+        :type durable: bit (as bit)
+        :param exclusive: Request an exclusive queue
+            Exclusive queues may only be accessed by the current connection, and are
+            deleted when that connection closes.  Passive declaration of an exclusive
+            queue by other connections are not allowed.
+        :type exclusive: bit (as bit)
+        :param auto_delete: Auto-delete queue when unused
+            If set, the queue is deleted when all consumers have finished using it.  The last
+            consumer can be cancelled either explicitly or because its channel is closed. If
+            there was no consumer ever on the queue, it won't be deleted.  Applications can
+            explicitly delete auto-delete queues using the Delete method as normal.
+        :type auto_delete: bit (as bit)
+        :type no_wait: no-wait (as bit)
+        :param arguments: Arguments for declaration
+            A set of arguments for the declaration. The syntax and semantics of these
+            arguments depends on the server implementation.
+        :type arguments: table (as table)
+        """
+        self.queue = queue
+        self.passive = passive
+        self.durable = durable
+        self.exclusive = exclusive
+        self.auto_delete = auto_delete
+        self.no_wait = no_wait
+        self.arguments = arguments
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class QueueDelete(AMQPMethod):
+    """
+    Delete a queue
+    
+    This method deletes a queue. When a queue is deleted any pending messages are sent
+    to a dead-letter queue if this is defined in the server configuration, and all
+    consumers on the queue are cancelled.
+    """
+    CLASS = Queue
+    NAME = u'delete'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 40
+    FULLNAME = u'queue.delete'
+    SYNCHRONOUS = True
+    REPLY_WITH = [QueueDeleteOk]
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'queue', u'queue-name', u'shortstr'), 
+        (u'if-unused', u'bit', u'bit'),  # delete only if unused
+        (u'if-empty', u'bit', u'bit'),  # delete only if empty
+        (u'no-wait', u'no-wait', u'bit'), 
+    ]
+
+    def __init__(self, queue, if_unused, if_empty, no_wait):
+        """
+        Create frame queue.delete
+
+        :param queue:             Specifies the name of the queue to delete.
+
+        :type queue: queue-name (as shortstr)
+        :param if_unused: Delete only if unused
+            If set, the server will only delete the queue if it has no consumers. If the
+            queue has consumers the server does does not delete it but raises a channel
+            exception instead.
+        :type if_unused: bit (as bit)
+        :param if_empty: Delete only if empty
+            If set, the server will only delete the queue if it has no messages.
+        :type if_empty: bit (as bit)
+        :type no_wait: no-wait (as bit)
+        """
+        self.queue = queue
+        self.if_unused = if_unused
+        self.if_empty = if_empty
+        self.no_wait = no_wait
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class QueueDeclareOk(AMQPMethod):
+    """
+    Confirms a queue definition
+    
+    This method confirms a Declare method and confirms the name of the queue, essential
+    for automatically-named queues.
+    """
+    CLASS = Queue
+    NAME = u'declare-ok'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 11
+    FULLNAME = u'queue.declare-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = QueueDeclare
+    FIELDS = [
+        (u'queue', u'queue-name', u'shortstr'), 
+        (u'message-count', u'message-count', u'long'), 
+        (u'consumer-count', u'long', u'long'),  # number of consumers
+    ]
+
+    def __init__(self, queue, message_count, consumer_count):
+        """
+        Create frame queue.declare-ok
+
+        :param queue: Reports the name of the queue. if the server generated a queue name, this field
+            contains that name.
+        :type queue: queue-name (as shortstr)
+        :type message_count: message-count (as long)
+        :param consumer_count: Number of consumers
+            Reports the number of active consumers for the queue. Note that consumers can
+            suspend activity (Channel.Flow) in which case they do not appear in this count.
+        :type consumer_count: long (as long)
+        """
+        self.queue = queue
+        self.message_count = message_count
+        self.consumer_count = consumer_count
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class QueueDeleteOk(AMQPMethod):
+    """
+    Confirm deletion of a queue
+    
+    This method confirms the deletion of a queue.
+    """
+    CLASS = Queue
+    NAME = u'delete-ok'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 41
+    FULLNAME = u'queue.delete-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = QueueDelete
+    FIELDS = [
+        (u'message-count', u'message-count', u'long'), 
+    ]
+
+    def __init__(self, message_count):
+        """
+        Create frame queue.delete-ok
+
+        :param message_count:             Reports the number of messages deleted.
+
+        :type message_count: message-count (as long)
+        """
+        self.message_count = message_count
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class QueuePurge(AMQPMethod):
+    """
+    Purge a queue
+    
+    This method removes all messages from a queue which are not awaiting
+    acknowledgment.
+    """
+    CLASS = Queue
+    NAME = u'purge'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 30
+    FULLNAME = u'queue.purge'
+    SYNCHRONOUS = True
+    REPLY_WITH = [QueuePurgeOk]
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'queue', u'queue-name', u'shortstr'), 
+        (u'no-wait', u'no-wait', u'bit'), 
+    ]
+
+    def __init__(self, queue, no_wait):
+        """
+        Create frame queue.purge
+
+        :param queue:             Specifies the name of the queue to purge.
+
+        :type queue: queue-name (as shortstr)
+        :type no_wait: no-wait (as bit)
+        """
+        self.queue = queue
+        self.no_wait = no_wait
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class QueuePurgeOk(AMQPMethod):
+    """
+    Confirms a queue purge
+    
+    This method confirms the purge of a queue.
+    """
+    CLASS = Queue
+    NAME = u'purge-ok'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 31
+    FULLNAME = u'queue.purge-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = QueuePurge
+    FIELDS = [
+        (u'message-count', u'message-count', u'long'), 
+    ]
+
+    def __init__(self, message_count):
+        """
+        Create frame queue.purge-ok
+
+        :param message_count:             Reports the number of messages purged.
+
+        :type message_count: message-count (as long)
+        """
+        self.message_count = message_count
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class QueueUnbind(AMQPMethod):
+    """
+    Unbind a queue from an exchange
+    
+    This method unbinds a queue from an exchange.
+    """
+    CLASS = Queue
+    NAME = u'unbind'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 50
+    FULLNAME = u'queue.unbind'
+    SYNCHRONOUS = True
+    REPLY_WITH = [QueueUnbindOk]
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'queue', u'queue-name', u'shortstr'), 
+        (u'exchange', u'exchange-name', u'shortstr'), 
+        (u'routing-key', u'shortstr', u'shortstr'),  # routing key of binding
+        (u'arguments', u'table', u'table'),  # arguments of binding
+    ]
+
+    def __init__(self, queue, exchange, routing_key, arguments):
+        """
+        Create frame queue.unbind
+
+        :param queue:             Specifies the name of the queue to unbind.
+
+        :type queue: queue-name (as shortstr)
+        :param exchange:             The name of the exchange to unbind from.
+
+        :type exchange: exchange-name (as shortstr)
+        :param routing_key: Routing key of binding
+            Specifies the routing key of the binding to unbind.
+        :type routing_key: shortstr (as shortstr)
+        :param arguments: Arguments of binding
+            Specifies the arguments of the binding to unbind.
+        :type arguments: table (as table)
+        """
+        self.queue = queue
+        self.exchange = exchange
+        self.routing_key = routing_key
+        self.arguments = arguments
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class QueueUnbindOk(AMQPMethod):
+    """
+    Confirm unbind successful
+    
+    This method confirms that the unbind was successful.
+    """
+    CLASS = Queue
+    NAME = u'unbind-ok'
+    CLASSNAME = u'queue'
+    CLASS_INDEX = 50
+    METHOD_INDEX = 51
+    FULLNAME = u'queue.unbind-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = QueueUnbind
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame queue.unbind-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+class Basic(AMQPClass):
+    """
+        The basic class provides methods that support an industry-standard messaging model.
+
+    """
+    NAME = u'basic'
+    INDEX = 60
+
+
+class BasicAck(AMQPMethod):
+    """
+    Acknowledge one or more messages
+    
+    This method acknowledges one or more messages delivered via the Deliver or Get-Ok
+    methods. The client can ask to confirm a single message or a set of messages up to
+    and including a specific message.
+    """
+    CLASS = Basic
+    NAME = u'ack'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 80
+    FULLNAME = u'basic.ack'
+    SYNCHRONOUS = False
+    REPLY_WITH = []
+    FIELDS = [
+        (u'delivery-tag', u'delivery-tag', u'longlong'), 
+        (u'multiple', u'bit', u'bit'),  # acknowledge multiple messages
+    ]
+
+    def __init__(self, delivery_tag, multiple):
+        """
+        Create frame basic.ack
+
+        :type delivery_tag: delivery-tag (as longlong)
+        :param multiple: Acknowledge multiple messages
+            If set to 1, the delivery tag is treated as "up to and including", so that the
+            client can acknowledge multiple messages with a single method. If set to zero,
+            the delivery tag refers to a single message. If the multiple field is 1, and the
+            delivery tag is zero, tells the server to acknowledge all outstanding messages.
+        :type multiple: bit (as bit)
+        """
+        self.delivery_tag = delivery_tag
+        self.multiple = multiple
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicConsume(AMQPMethod):
+    """
+    Start a queue consumer
+    
+    This method asks the server to start a "consumer", which is a transient request for
+    messages from a specific queue. Consumers last as long as the channel they were
+    declared on, or until the client cancels them.
+    """
+    CLASS = Basic
+    NAME = u'consume'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 20
+    FULLNAME = u'basic.consume'
+    SYNCHRONOUS = True
+    REPLY_WITH = [BasicConsumeOk]
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'queue', u'queue-name', u'shortstr'), 
+        (u'consumer-tag', u'consumer-tag', u'shortstr'), 
+        (u'no-local', u'no-local', u'bit'), 
+        (u'no-ack', u'no-ack', u'bit'), 
+        (u'exclusive', u'bit', u'bit'),  # request exclusive access
+        (u'no-wait', u'no-wait', u'bit'), 
+        (u'arguments', u'table', u'table'),  # arguments for declaration
+    ]
+
+    def __init__(self, queue, consumer_tag, no_local, no_ack, exclusive, no_wait, arguments):
+        """
+        Create frame basic.consume
+
+        :param queue:             Specifies the name of the queue to consume from.
+
+        :type queue: queue-name (as shortstr)
+        :param consumer_tag: Specifies the identifier for the consumer. the consumer tag is local to a
+            channel, so two clients can use the same consumer tags. If this field is
+            empty the server will generate a unique tag.
+        :type consumer_tag: consumer-tag (as shortstr)
+        :type no_local: no-local (as bit)
+        :type no_ack: no-ack (as bit)
+        :param exclusive: Request exclusive access
+            Request exclusive consumer access, meaning only this consumer can access the
+            queue.
+        :type exclusive: bit (as bit)
+        :type no_wait: no-wait (as bit)
+        :param arguments: Arguments for declaration
+            A set of arguments for the consume. The syntax and semantics of these
+            arguments depends on the server implementation.
+        :type arguments: table (as table)
+        """
+        self.queue = queue
+        self.consumer_tag = consumer_tag
+        self.no_local = no_local
+        self.no_ack = no_ack
+        self.exclusive = exclusive
+        self.no_wait = no_wait
+        self.arguments = arguments
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicCancel(AMQPMethod):
+    """
+    End a queue consumer
+    
+    This method cancels a consumer. This does not affect already delivered
+    messages, but it does mean the server will not send any more messages for
+    that consumer. The client may receive an arbitrary number of messages in
+    between sending the cancel method and receiving the cancel-ok reply.
+    """
+    CLASS = Basic
+    NAME = u'cancel'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 30
+    FULLNAME = u'basic.cancel'
+    SYNCHRONOUS = True
+    REPLY_WITH = [BasicCancelOk]
+    FIELDS = [
+        (u'consumer-tag', u'consumer-tag', u'shortstr'), 
+        (u'no-wait', u'no-wait', u'bit'), 
+    ]
+
+    def __init__(self, consumer_tag, no_wait):
+        """
+        Create frame basic.cancel
+
+        :type consumer_tag: consumer-tag (as shortstr)
+        :type no_wait: no-wait (as bit)
+        """
+        self.consumer_tag = consumer_tag
+        self.no_wait = no_wait
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicConsumeOk(AMQPMethod):
+    """
+    Confirm a new consumer
+    
+    The server provides the client with a consumer tag, which is used by the client
+    for methods called on the consumer at a later stage.
+    """
+    CLASS = Basic
+    NAME = u'consume-ok'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 21
+    FULLNAME = u'basic.consume-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = BasicConsume
+    FIELDS = [
+        (u'consumer-tag', u'consumer-tag', u'shortstr'), 
+    ]
+
+    def __init__(self, consumer_tag):
+        """
+        Create frame basic.consume-ok
+
+        :param consumer_tag:             Holds the consumer tag specified by the client or provided by the server.
+
+        :type consumer_tag: consumer-tag (as shortstr)
+        """
+        self.consumer_tag = consumer_tag
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicCancelOk(AMQPMethod):
+    """
+    Confirm a cancelled consumer
+    
+    This method confirms that the cancellation was completed.
+    """
+    CLASS = Basic
+    NAME = u'cancel-ok'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 31
+    FULLNAME = u'basic.cancel-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = BasicCancel
+    FIELDS = [
+        (u'consumer-tag', u'consumer-tag', u'shortstr'), 
+    ]
+
+    def __init__(self, consumer_tag):
+        """
+        Create frame basic.cancel-ok
+
+        :type consumer_tag: consumer-tag (as shortstr)
+        """
+        self.consumer_tag = consumer_tag
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicDeliver(AMQPMethod):
+    """
+    Notify the client of a consumer message
+    
+    This method delivers a message to the client, via a consumer. In the asynchronous
+    message delivery model, the client starts a consumer using the Consume method, then
+    the server responds with Deliver methods as and when messages arrive for that
+    consumer.
+    """
+    CLASS = Basic
+    NAME = u'deliver'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 60
+    FULLNAME = u'basic.deliver'
+    SYNCHRONOUS = False
+    REPLY_WITH = []
+    FIELDS = [
+        (u'consumer-tag', u'consumer-tag', u'shortstr'), 
+        (u'delivery-tag', u'delivery-tag', u'longlong'), 
+        (u'redelivered', u'redelivered', u'bit'), 
+        (u'exchange', u'exchange-name', u'shortstr'), 
+        (u'routing-key', u'shortstr', u'shortstr'),  # Message routing key
+    ]
+
+    def __init__(self, consumer_tag, delivery_tag, redelivered, exchange, routing_key):
+        """
+        Create frame basic.deliver
+
+        :type consumer_tag: consumer-tag (as shortstr)
+        :type delivery_tag: delivery-tag (as longlong)
+        :type redelivered: redelivered (as bit)
+        :param exchange: Specifies the name of the exchange that the message was originally published to.
+            May be empty, indicating the default exchange.
+        :type exchange: exchange-name (as shortstr)
+        :param routing_key: Message routing key
+            Specifies the routing key name specified when the message was published.
+        :type routing_key: shortstr (as shortstr)
+        """
+        self.consumer_tag = consumer_tag
+        self.delivery_tag = delivery_tag
+        self.redelivered = redelivered
+        self.exchange = exchange
+        self.routing_key = routing_key
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicGet(AMQPMethod):
+    """
+    Direct access to a queue
+    
+    This method provides a direct access to the messages in a queue using a synchronous
+    dialogue that is designed for specific types of application where synchronous
+    functionality is more important than performance.
+    """
+    CLASS = Basic
+    NAME = u'get'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 70
+    FULLNAME = u'basic.get'
+    SYNCHRONOUS = True
+    REPLY_WITH = [BasicGetOk, BasicGetEmpty]
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'queue', u'queue-name', u'shortstr'), 
+        (u'no-ack', u'no-ack', u'bit'), 
+    ]
+
+    def __init__(self, queue, no_ack):
+        """
+        Create frame basic.get
+
+        :param queue:             Specifies the name of the queue to get a message from.
+
+        :type queue: queue-name (as shortstr)
+        :type no_ack: no-ack (as bit)
+        """
+        self.queue = queue
+        self.no_ack = no_ack
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicGetOk(AMQPMethod):
+    """
+    Provide client with a message
+    
+    This method delivers a message to the client following a get method. A message
+    delivered by 'get-ok' must be acknowledged unless the no-ack option was set in the
+    get method.
+    """
+    CLASS = Basic
+    NAME = u'get-ok'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 71
+    FULLNAME = u'basic.get-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = BasicGet
+    FIELDS = [
+        (u'delivery-tag', u'delivery-tag', u'longlong'), 
+        (u'redelivered', u'redelivered', u'bit'), 
+        (u'exchange', u'exchange-name', u'shortstr'), 
+        (u'routing-key', u'shortstr', u'shortstr'),  # Message routing key
+        (u'message-count', u'message-count', u'long'), 
+    ]
+
+    def __init__(self, delivery_tag, redelivered, exchange, routing_key, message_count):
+        """
+        Create frame basic.get-ok
+
+        :type delivery_tag: delivery-tag (as longlong)
+        :type redelivered: redelivered (as bit)
+        :param exchange: Specifies the name of the exchange that the message was originally published to.
+            If empty, the message was published to the default exchange.
+        :type exchange: exchange-name (as shortstr)
+        :param routing_key: Message routing key
+            Specifies the routing key name specified when the message was published.
+        :type routing_key: shortstr (as shortstr)
+        :type message_count: message-count (as long)
+        """
+        self.delivery_tag = delivery_tag
+        self.redelivered = redelivered
+        self.exchange = exchange
+        self.routing_key = routing_key
+        self.message_count = message_count
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicGetEmpty(AMQPMethod):
+    """
+    Indicate no messages available
+    
+    This method tells the client that the queue has no messages available for the
+    client.
+    """
+    CLASS = Basic
+    NAME = u'get-empty'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 72
+    FULLNAME = u'basic.get-empty'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = BasicGet
+    FIELDS = [
+        (u'reserved-1', u'shortstr', u'shortstr'), 
+    ]
+
+    def __init__(self):
+        """
+        Create frame basic.get-empty
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicPublish(AMQPMethod):
+    """
+    Publish a message
+    
+    This method publishes a message to a specific exchange. The message will be routed
+    to queues as defined by the exchange configuration and distributed to any active
+    consumers when the transaction, if any, is committed.
+    """
+    CLASS = Basic
+    NAME = u'publish'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 40
+    FULLNAME = u'basic.publish'
+    SYNCHRONOUS = False
+    REPLY_WITH = []
+    FIELDS = [
+        (u'reserved-1', u'short', u'short'), 
+        (u'exchange', u'exchange-name', u'shortstr'), 
+        (u'routing-key', u'shortstr', u'shortstr'),  # Message routing key
+        (u'mandatory', u'bit', u'bit'),  # indicate mandatory routing
+        (u'immediate', u'bit', u'bit'),  # request immediate delivery
+    ]
+
+    def __init__(self, exchange, routing_key, mandatory, immediate):
+        """
+        Create frame basic.publish
+
+        :param exchange: Specifies the name of the exchange to publish to. the exchange name can be
+            empty, meaning the default exchange. If the exchange name is specified, and that
+            exchange does not exist, the server will raise a channel exception.
+        :type exchange: exchange-name (as shortstr)
+        :param routing_key: Message routing key
+            Specifies the routing key for the message. The routing key is used for routing
+            messages depending on the exchange configuration.
+        :type routing_key: shortstr (as shortstr)
+        :param mandatory: Indicate mandatory routing
+            This flag tells the server how to react if the message cannot be routed to a
+            queue. If this flag is set, the server will return an unroutable message with a
+            Return method. If this flag is zero, the server silently drops the message.
+        :type mandatory: bit (as bit)
+        :param immediate: Request immediate delivery
+            This flag tells the server how to react if the message cannot be routed to a
+            queue consumer immediately. If this flag is set, the server will return an
+            undeliverable message with a Return method. If this flag is zero, the server
+            will queue the message, but with no guarantee that it will ever be consumed.
+        :type immediate: bit (as bit)
+        """
+        self.exchange = exchange
+        self.routing_key = routing_key
+        self.mandatory = mandatory
+        self.immediate = immediate
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicQos(AMQPMethod):
+    """
+    Specify quality of service
+    
+    This method requests a specific quality of service. The QoS can be specified for the
+    current channel or for all channels on the connection. The particular properties and
+    semantics of a qos method always depend on the content class semantics. Though the
+    qos method could in principle apply to both peers, it is currently meaningful only
+    for the server.
+    """
+    CLASS = Basic
+    NAME = u'qos'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 10
+    FULLNAME = u'basic.qos'
+    SYNCHRONOUS = True
+    REPLY_WITH = [BasicQosOk]
+    FIELDS = [
+        (u'prefetch-size', u'long', u'long'),  # prefetch window in octets
+        (u'prefetch-count', u'short', u'short'),  # prefetch window in messages
+        (u'global', u'bit', u'bit'),  # apply to entire connection
+    ]
+
+    def __init__(self, prefetch_size, prefetch_count, global_):
+        """
+        Create frame basic.qos
+
+        :param prefetch_size: Prefetch window in octets
+            The client can request that messages be sent in advance so that when the client
+            finishes processing a message, the following message is already held locally,
+            rather than needing to be sent down the channel. Prefetching gives a performance
+            improvement. This field specifies the prefetch window size in octets. The server
+            will send a message in advance if it is equal to or smaller in size than the
+            available prefetch size (and also falls into other prefetch limits). May be set
+            to zero, meaning "no specific limit", although other prefetch limits may still
+            apply. The prefetch-size is ignored if the no-ack option is set.
+        :type prefetch_size: long (as long)
+        :param prefetch_count: Prefetch window in messages
+            Specifies a prefetch window in terms of whole messages. This field may be used
+            in combination with the prefetch-size field; a message will only be sent in
+            advance if both prefetch windows (and those at the channel and connection level)
+            allow it. The prefetch-count is ignored if the no-ack option is set.
+        :type prefetch_count: short (as short)
+        :param global_: Apply to entire connection
+            By default the QoS settings apply to the current channel only. If this field is
+            set, they are applied to the entire connection.
+        :type global_: bit (as bit)
+        """
+        self.prefetch_size = prefetch_size
+        self.prefetch_count = prefetch_count
+        self.global_ = global_
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicQosOk(AMQPMethod):
+    """
+    Confirm the requested qos
+    
+    This method tells the client that the requested QoS levels could be handled by the
+    server. The requested QoS applies to all active consumers until a new QoS is
+    defined.
+    """
+    CLASS = Basic
+    NAME = u'qos-ok'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 11
+    FULLNAME = u'basic.qos-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = BasicQos
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame basic.qos-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicReturn(AMQPMethod):
+    """
+    Return a failed message
+    
+    This method returns an undeliverable message that was published with the "immediate"
+    flag set, or an unroutable message published with the "mandatory" flag set. The
+    reply code and text provide information about the reason that the message was
+    undeliverable.
+    """
+    CLASS = Basic
+    NAME = u'return'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 50
+    FULLNAME = u'basic.return'
+    SYNCHRONOUS = False
+    REPLY_WITH = []
+    FIELDS = [
+        (u'reply-code', u'reply-code', u'short'), 
+        (u'reply-text', u'reply-text', u'shortstr'), 
+        (u'exchange', u'exchange-name', u'shortstr'), 
+        (u'routing-key', u'shortstr', u'shortstr'),  # Message routing key
+    ]
+
+    def __init__(self, reply_code, reply_text, exchange, routing_key):
+        """
+        Create frame basic.return
+
+        :type reply_code: reply-code (as short)
+        :type reply_text: reply-text (as shortstr)
+        :param exchange: Specifies the name of the exchange that the message was originally published
+            to.  May be empty, meaning the default exchange.
+        :type exchange: exchange-name (as shortstr)
+        :param routing_key: Message routing key
+            Specifies the routing key name specified when the message was published.
+        :type routing_key: shortstr (as shortstr)
+        """
+        self.reply_code = reply_code
+        self.reply_text = reply_text
+        self.exchange = exchange
+        self.routing_key = routing_key
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicReject(AMQPMethod):
+    """
+    Reject an incoming message
+    
+    This method allows a client to reject a message. It can be used to interrupt and
+    cancel large incoming messages, or return untreatable messages to their original
+    queue.
+    """
+    CLASS = Basic
+    NAME = u'reject'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 90
+    FULLNAME = u'basic.reject'
+    SYNCHRONOUS = False
+    REPLY_WITH = []
+    FIELDS = [
+        (u'delivery-tag', u'delivery-tag', u'longlong'), 
+        (u'requeue', u'bit', u'bit'),  # requeue the message
+    ]
+
+    def __init__(self, delivery_tag, requeue):
+        """
+        Create frame basic.reject
+
+        :type delivery_tag: delivery-tag (as longlong)
+        :param requeue: Requeue the message
+            If requeue is true, the server will attempt to requeue the message.  If requeue
+            is false or the requeue  attempt fails the messages are discarded or dead-lettered.
+        :type requeue: bit (as bit)
+        """
+        self.delivery_tag = delivery_tag
+        self.requeue = requeue
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicRecoverAsync(AMQPMethod):
+    """
+    Redeliver unacknowledged messages
+    
+    This method asks the server to redeliver all unacknowledged messages on a
+    specified channel. Zero or more messages may be redelivered.  This method
+    is deprecated in favour of the synchronous Recover/Recover-Ok.
+    """
+    CLASS = Basic
+    NAME = u'recover-async'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 100
+    FULLNAME = u'basic.recover-async'
+    SYNCHRONOUS = False
+    REPLY_WITH = []
+    FIELDS = [
+        (u'requeue', u'bit', u'bit'),  # requeue the message
+    ]
+
+    def __init__(self, requeue):
+        """
+        Create frame basic.recover-async
+
+        :param requeue: Requeue the message
+            If this field is zero, the message will be redelivered to the original
+            recipient. If this bit is 1, the server will attempt to requeue the message,
+            potentially then delivering it to an alternative subscriber.
+        :type requeue: bit (as bit)
+        """
+        self.requeue = requeue
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicRecover(AMQPMethod):
+    """
+    Redeliver unacknowledged messages
+    
+    This method asks the server to redeliver all unacknowledged messages on a
+    specified channel. Zero or more messages may be redelivered.  This method
+    replaces the asynchronous Recover.
+    """
+    CLASS = Basic
+    NAME = u'recover'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 110
+    FULLNAME = u'basic.recover'
+    SYNCHRONOUS = False
+    REPLY_WITH = []
+    FIELDS = [
+        (u'requeue', u'bit', u'bit'),  # requeue the message
+    ]
+
+    def __init__(self, requeue):
+        """
+        Create frame basic.recover
+
+        :param requeue: Requeue the message
+            If this field is zero, the message will be redelivered to the original
+            recipient. If this bit is 1, the server will attempt to requeue the message,
+            potentially then delivering it to an alternative subscriber.
+        :type requeue: bit (as bit)
+        """
+        self.requeue = requeue
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class BasicRecoverOk(AMQPMethod):
+    """
+    Confirm recovery
+    
+    This method acknowledges a Basic.Recover method.
+    """
+    CLASS = Basic
+    NAME = u'recover-ok'
+    CLASSNAME = u'basic'
+    CLASS_INDEX = 60
+    METHOD_INDEX = 111
+    FULLNAME = u'basic.recover-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame basic.recover-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+class Tx(AMQPClass):
+    """
+    The tx class allows publish and ack operations to be batched into atomic
+    
+    units of work.  The intention is that all publish and ack requests issued
+    within a transaction will complete successfully or none of them will.
+    Servers SHOULD implement atomic transactions at least where all publish
+    or ack requests affect a single queue.  Transactions that cover multiple
+    queues may be non-atomic, given that queues can be created and destroyed
+    asynchronously, and such events do not form part of any transaction.
+    Further, the behaviour of transactions with respect to the immediate and
+    mandatory flags on Basic.Publish methods is not defined.
+    """
+    NAME = u'tx'
+    INDEX = 90
+
+
+class TxCommit(AMQPMethod):
+    """
+    Commit the current transaction
+    
+    This method commits all message publications and acknowledgments performed in
+    the current transaction.  A new transaction starts immediately after a commit.
+    """
+    CLASS = Tx
+    NAME = u'commit'
+    CLASSNAME = u'tx'
+    CLASS_INDEX = 90
+    METHOD_INDEX = 20
+    FULLNAME = u'tx.commit'
+    SYNCHRONOUS = True
+    REPLY_WITH = [TxCommitOk]
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame tx.commit
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class TxCommitOk(AMQPMethod):
+    """
+    Confirm a successful commit
+    
+    This method confirms to the client that the commit succeeded. Note that if a commit
+    fails, the server raises a channel exception.
+    """
+    CLASS = Tx
+    NAME = u'commit-ok'
+    CLASSNAME = u'tx'
+    CLASS_INDEX = 90
+    METHOD_INDEX = 21
+    FULLNAME = u'tx.commit-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = TxCommit
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame tx.commit-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class TxRollback(AMQPMethod):
+    """
+    Abandon the current transaction
+    
+    This method abandons all message publications and acknowledgments performed in
+    the current transaction. A new transaction starts immediately after a rollback.
+    Note that unacked messages will not be automatically redelivered by rollback;
+    if that is required an explicit recover call should be issued.
+    """
+    CLASS = Tx
+    NAME = u'rollback'
+    CLASSNAME = u'tx'
+    CLASS_INDEX = 90
+    METHOD_INDEX = 30
+    FULLNAME = u'tx.rollback'
+    SYNCHRONOUS = True
+    REPLY_WITH = [TxRollbackOk]
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame tx.rollback
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class TxRollbackOk(AMQPMethod):
+    """
+    Confirm successful rollback
+    
+    This method confirms to the client that the rollback succeeded. Note that if an
+    rollback fails, the server raises a channel exception.
+    """
+    CLASS = Tx
+    NAME = u'rollback-ok'
+    CLASSNAME = u'tx'
+    CLASS_INDEX = 90
+    METHOD_INDEX = 31
+    FULLNAME = u'tx.rollback-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = TxRollback
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame tx.rollback-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class TxSelect(AMQPMethod):
+    """
+    Select standard transaction mode
+    
+    This method sets the channel to use standard transactions. The client must use this
+    method at least once on a channel before using the Commit or Rollback methods.
+    """
+    CLASS = Tx
+    NAME = u'select'
+    CLASSNAME = u'tx'
+    CLASS_INDEX = 90
+    METHOD_INDEX = 10
+    FULLNAME = u'tx.select'
+    SYNCHRONOUS = True
+    REPLY_WITH = [TxSelectOk]
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame tx.select
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+class TxSelectOk(AMQPMethod):
+    """
+    Confirm transaction mode
+    
+    This method confirms to the client that the channel was successfully set to use
+    standard transactions.
+    """
+    CLASS = Tx
+    NAME = u'select-ok'
+    CLASSNAME = u'tx'
+    CLASS_INDEX = 90
+    METHOD_INDEX = 11
+    FULLNAME = u'tx.select-ok'
+    SYNCHRONOUS = True
+    REPLY_WITH = []
+    RESPONSE_TO = TxSelect
+    FIELDS = [
+    ]
+
+    def __init__(self):
+        """
+        Create frame tx.select-ok
+
+        """
+
+    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+
+IDENT_TO_METHOD = {
+    (90, 21): TxCommitOk,
+    (60, 100): BasicRecoverAsync,
+    (10, 11): ConnectionStartOk,
+    (60, 40): BasicPublish,
+    (60, 50): BasicReturn,
+    (10, 51): ConnectionCloseOk,
+    (20, 20): ChannelFlow,
+    (60, 21): BasicConsumeOk,
+    (10, 21): ConnectionSecureOk,
+    (90, 30): TxRollback,
+    (90, 10): TxSelect,
+    (50, 11): QueueDeclareOk,
+    (60, 70): BasicGet,
+    (90, 11): TxSelectOk,
+    (10, 30): ConnectionTune,
+    (60, 11): BasicQosOk,
+    (60, 80): BasicAck,
+    (20, 21): ChannelFlowOk,
+    (60, 60): BasicDeliver,
+    (90, 31): TxRollbackOk,
+    (20, 40): ChannelClose,
+    (60, 71): BasicGetOk,
+    (50, 30): QueuePurge,
+    (10, 31): ConnectionTuneOk,
+    (10, 40): ConnectionOpen,
+    (60, 30): BasicCancel,
+    (50, 50): QueueUnbind,
+    (40, 10): ExchangeDeclare,
+    (10, 50): ConnectionClose,
+    (20, 10): ChannelOpen,
+    (20, 41): ChannelCloseOk,
+    (60, 110): BasicRecover,
+    (60, 90): BasicReject,
+    (50, 31): QueuePurgeOk,
+    (50, 40): QueueDelete,
+    (40, 20): ExchangeDelete,
+    (50, 20): QueueBind,
+    (10, 41): ConnectionOpenOk,
+    (60, 31): BasicCancelOk,
+    (90, 20): TxCommit,
+    (10, 10): ConnectionStart,
+    (60, 10): BasicQos,
+    (40, 11): ExchangeDeclareOk,
+    (40, 21): ExchangeDeleteOk,
+    (20, 11): ChannelOpenOk,
+    (60, 72): BasicGetEmpty,
+    (60, 111): BasicRecoverOk,
+    (60, 20): BasicConsume,
+    (10, 20): ConnectionSecure,
+    (50, 41): QueueDeleteOk,
+    (50, 51): QueueUnbindOk,
+    (50, 21): QueueBindOk,
+    (50, 10): QueueDeclare,
+}
+
diff --git a/coolamqp/framing/serialization.py b/coolamqp/framing/serialization.py
new file mode 100644
index 0000000000000000000000000000000000000000..1aacd3177cfc98a5e36aa5f6ec7332d9b6550c71
--- /dev/null
+++ b/coolamqp/framing/serialization.py
@@ -0,0 +1,19 @@
+# coding=UTF-8
+from __future__ import absolute_import, division, print_function
+import struct
+"""bytes <-> Frame's"""
+
+from coolamqp.framing.definitions import FRAME_END
+
+HDR = b'AMQP\x01\x01\x00\x09'
+
+
+
+def to_packet(type_, channel, payload, size=None, frame_end=None):
+    """
+    :type payload: six.binary_type
+    :type frame_end: six.binary_type
+    """
+    size = size or len(payload)
+    frame_end = frame_end or FRAME_END
+    return struct.pack('!BHI', type_, channel, size) + payload + FRAME_END
diff --git a/resources/amqp0-9-1.xml b/resources/amqp0-9-1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..da785eb3bed370d7c11852fce8ef7fe7f366f2f6
--- /dev/null
+++ b/resources/amqp0-9-1.xml
@@ -0,0 +1,2843 @@
+<?xml version = "1.0"?>
+<!--
+    Copyright Notice
+    ================
+    Copyright (c) 2006-2008 Cisco Systems, Credit Suisse, Deutsche Boerse
+    Systems, Envoy Technologies, Inc., Goldman Sachs, IONA Technologies PLC,
+    iMatix Corporation, JPMorgan Chase Bank Inc. N.A, Novell, Rabbit
+    Technologies Ltd., Red Hat, Inc., TWIST Process Innovations Ltd, WS02
+    Inc. and 29West Inc. All rights reserved.
+
+    License
+    =======
+    Cisco Systems, Credit Suisse, Deutsche Boerse Systems, Envoy Technologies,
+    Inc., Goldman Sachs, IONA Technologies PLC, iMatix Corporation, JPMorgan
+    Chase Bank Inc. N.A, Novell, Rabbit Technologies Ltd., Red Hat, Inc.,
+    TWIST Process Innovations Ltd, WS02, Inc. and 29West Inc. (collectively,
+    the "Authors") each hereby grants to you a worldwide, perpetual,
+    royalty-free, nontransferable, nonexclusive license to (i) copy, display,
+    distribute and implement the Advanced Messaging Queue Protocol ("AMQP")
+    Specification and (ii) the Licensed Claims that are held by the Authors,
+    all for the purpose of implementing the Advanced Messaging Queue Protocol
+    Specification. Your license and any rights under this Agreement will
+    terminate immediately without notice from any Author if you bring any
+    claim, suit, demand, or action related to the Advanced Messaging Queue
+    Protocol Specification against any Author. Upon termination, you shall
+    destroy all copies of the Advanced Messaging Queue Protocol Specification
+    in your possession or control.
+
+    As used hereunder, "Licensed Claims" means those claims of a patent or
+    patent application, throughout the world, excluding design patents and
+    design registrations, owned or controlled, or that can be sublicensed
+    without fee and in compliance with the requirements of this Agreement,
+    by an Author or its affiliates now or at any future time and which would
+    necessarily be infringed by implementation of the Advanced Messaging
+    Queue Protocol Specification. A claim is necessarily infringed hereunder
+    only when it is not possible to avoid infringing it because there is no
+    plausible non-infringing alternative for implementing the required
+    portions of the Advanced Messaging Queue Protocol Specification.
+    Notwithstanding the foregoing, Licensed Claims shall not include any
+    claims other than as set forth above even if contained in the same patent
+    as Licensed Claims; or that read solely on any implementations of any
+    portion of the Advanced Messaging Queue Protocol Specification that are
+    not required by the Advanced Messaging Queue ProtocolSpecification, or
+    that, if licensed, would require a payment of royalties by the licensor
+    to unaffiliated third parties. Moreover, Licensed Claims shall not
+    include (i) any enabling technologies that may be necessary to make or
+    use any Licensed Product but are not themselves expressly set forth in
+    the Advanced Messaging Queue Protocol Specification (e.g., semiconductor
+    manufacturing technology, compiler technology, object oriented
+    technology, networking technology, operating system technology, and the
+    like); or (ii) the implementation of other published standards developed
+    elsewhere and merely referred to in the body of the Advanced Messaging
+    Queue Protocol Specification, or (iii) any Licensed Product and any
+    combinations thereof the purpose or function of which is not required
+    for compliance with the Advanced Messaging Queue Protocol Specification.
+    For purposes of this definition, the Advanced Messaging Queue Protocol
+    Specification shall be deemed to include both architectural and
+    interconnection requirements essential for interoperability and may also
+    include supporting source code artifacts where such architectural,
+    interconnection requirements and source code artifacts are expressly
+    identified as being required or documentation to achieve compliance with
+    the Advanced Messaging Queue Protocol Specification.
+
+    As used hereunder, "Licensed Products" means only those specific portions
+    of products (hardware, software or combinations thereof) that implement
+    and are compliant with all relevant portions of the Advanced Messaging
+    Queue Protocol Specification.
+
+    The following disclaimers, which you hereby also acknowledge as to any
+    use you may make of the Advanced Messaging Queue Protocol Specification:
+
+    THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION IS PROVIDED "AS IS,"
+    AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+    IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE
+    CONTENTS OF THE ADVANCED MESSAGING QUEUE PROTOCOL SPECIFICATION ARE
+    SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF THE ADVANCED
+    MESSAGING QUEUE PROTOCOL SPECIFICATION WILL NOT INFRINGE ANY THIRD PARTY
+    PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+    THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL,
+    INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY
+    USE, IMPLEMENTATION OR DISTRIBUTION OF THE ADVANCED MESSAGING QUEUE
+    PROTOCOL SPECIFICATION.
+
+    The name and trademarks of the Authors may NOT be used in any manner,
+    including advertising or publicity pertaining to the Advanced Messaging
+    Queue Protocol Specification or its contents without specific, written
+    prior permission. Title to copyright in the Advanced Messaging Queue
+    Protocol Specification will at all times remain with the Authors.
+
+    No other rights are granted by implication, estoppel or otherwise.
+
+    Upon termination of your license or rights under this Agreement, you
+    shall destroy all copies of the Advanced Messaging Queue Protocol
+    Specification in your possession or control.
+
+    Trademarks
+    ==========
+    JPMorgan, JPMorgan Chase, Chase, the JPMorgan Chase logo and the
+    Octagon Symbol are trademarks of JPMorgan Chase & Co.
+
+    IMATIX and the iMatix logo are trademarks of iMatix Corporation sprl.
+
+    IONA, IONA Technologies, and the IONA logos are trademarks of IONA
+    Technologies PLC and/or its subsidiaries.
+
+    LINUX is a trademark of Linus Torvalds. RED HAT and JBOSS are registered
+    trademarks of Red Hat, Inc. in the US and other countries.
+
+    Java, all Java-based trademarks and OpenOffice.org are trademarks of
+    Sun Microsystems, Inc. in the United States, other countries, or both.
+
+    Other company, product, or service names may be trademarks or service
+    marks of others.
+
+    Links to full AMQP specification:
+    =================================
+    http://www.amqp.org
+-->
+
+<!--
+    <!DOCTYPE amqp SYSTEM "amqp.dtd">
+-->
+
+<!-- XML Notes
+
+    We use entities to indicate repetition; attributes to indicate properties.
+
+    We use the 'name' attribute as an identifier, usually within the context
+    of the surrounding entities.
+
+    We use spaces to seperate words in names, so that we can print names in
+    their natural form depending on the context - underlines for source code,
+    hyphens for written text, etc.
+
+    We do not enforce any particular validation mechanism but we support all
+    mechanisms.  The protocol definition conforms to a formal grammar that is
+    published seperately in several technologies.
+
+ -->
+
+<amqp major = "0" minor = "9" revision = "1"
+    port = "5672" comment = "AMQ Protocol version 0-9-1">
+  <!--
+      ======================================================
+      ==       CONSTANTS
+      ======================================================
+  -->
+  <!-- Frame types -->
+  <constant name = "frame-method"     value = "1" />
+  <constant name = "frame-header"     value = "2" />
+  <constant name = "frame-body"       value = "3" />
+  <constant name = "frame-heartbeat"  value = "8" />
+
+  <!-- Protocol constants -->
+  <constant name = "frame-min-size"   value = "4096" />
+  <constant name = "frame-end"        value = "206" />
+
+  <!-- Reply codes -->
+  <constant name = "reply-success" value = "200">
+    <doc>
+      Indicates that the method completed successfully. This reply code is
+      reserved for future use - the current protocol design does not use positive
+      confirmation and reply codes are sent only in case of an error.
+    </doc>
+  </constant>
+
+  <constant name = "content-too-large" value = "311" class = "soft-error">
+    <doc>
+      The client attempted to transfer content larger than the server could accept
+      at the present time. The client may retry at a later time.
+    </doc>
+  </constant>
+
+  <constant name = "no-consumers" value = "313" class = "soft-error">
+    <doc>
+      When the exchange cannot deliver to a consumer when the immediate flag is
+      set. As a result of pending data on the queue or the absence of any
+      consumers of the queue.
+    </doc>
+  </constant>
+
+  <constant name = "connection-forced" value = "320" class = "hard-error">
+    <doc>
+      An operator intervened to close the connection for some reason. The client
+      may retry at some later date.
+    </doc>
+  </constant>
+
+  <constant name = "invalid-path" value = "402" class = "hard-error">
+    <doc>
+      The client tried to work with an unknown virtual host.
+    </doc>
+  </constant>
+
+  <constant name = "access-refused" value = "403" class = "soft-error">
+    <doc>
+      The client attempted to work with a server entity to which it has no
+      access due to security settings.
+    </doc>
+  </constant>
+
+  <constant name = "not-found" value = "404" class = "soft-error">
+    <doc>
+      The client attempted to work with a server entity that does not exist.
+    </doc>
+  </constant>
+
+  <constant name = "resource-locked" value = "405" class = "soft-error">
+    <doc>
+      The client attempted to work with a server entity to which it has no
+      access because another client is working with it.
+    </doc>
+  </constant>
+
+  <constant name = "precondition-failed" value = "406" class = "soft-error">
+    <doc>
+      The client requested a method that was not allowed because some precondition
+      failed.
+    </doc>
+  </constant>
+
+  <constant name = "frame-error" value = "501" class = "hard-error">
+    <doc>
+      The sender sent a malformed frame that the recipient could not decode.
+      This strongly implies a programming error in the sending peer.
+    </doc>
+  </constant>
+
+  <constant name = "syntax-error" value = "502" class = "hard-error">
+    <doc>
+      The sender sent a frame that contained illegal values for one or more
+      fields. This strongly implies a programming error in the sending peer.
+    </doc>
+  </constant>
+
+  <constant name = "command-invalid" value = "503" class = "hard-error">
+    <doc>
+      The client sent an invalid sequence of frames, attempting to perform an
+      operation that was considered invalid by the server. This usually implies
+      a programming error in the client.
+    </doc>
+  </constant>
+
+  <constant name = "channel-error" value = "504" class = "hard-error">
+    <doc>
+      The client attempted to work with a channel that had not been correctly
+      opened. This most likely indicates a fault in the client layer.
+    </doc>
+  </constant>
+
+  <constant name = "unexpected-frame" value = "505" class = "hard-error">
+    <doc>
+      The peer sent a frame that was not expected, usually in the context of
+      a content header and body.  This strongly indicates a fault in the peer's
+      content processing.
+    </doc>
+  </constant>
+
+  <constant name = "resource-error" value = "506" class = "hard-error">
+    <doc>
+      The server could not complete the method because it lacked sufficient
+      resources. This may be due to the client creating too many of some type
+      of entity.
+    </doc>
+  </constant>
+
+  <constant name = "not-allowed" value = "530" class = "hard-error">
+    <doc>
+      The client tried to work with some entity in a manner that is prohibited
+      by the server, due to security settings or by some other criteria.
+    </doc>
+  </constant>
+
+  <constant name = "not-implemented" value = "540" class = "hard-error">
+    <doc>
+      The client tried to use functionality that is not implemented in the
+      server.
+    </doc>
+  </constant>
+
+  <constant name = "internal-error" value = "541" class = "hard-error">
+    <doc>
+      The server could not complete the method because of an internal error.
+      The server may require intervention by an operator in order to resume
+      normal operations.
+    </doc>
+  </constant>
+
+  <!--
+      ======================================================
+      ==       DOMAIN TYPES
+      ======================================================
+  -->
+
+  <domain name = "class-id" type = "short" />
+
+  <domain name = "consumer-tag" type = "shortstr" label = "consumer tag">
+    <doc>
+      Identifier for the consumer, valid within the current channel.
+    </doc>
+  </domain>
+
+  <domain name = "delivery-tag" type = "longlong" label = "server-assigned delivery tag">
+    <doc>
+      The server-assigned and channel-specific delivery tag
+    </doc>
+    <rule name = "channel-local">
+      <doc>
+        The delivery tag is valid only within the channel from which the message was
+        received. I.e. a client MUST NOT receive a message on one channel and then
+        acknowledge it on another.
+      </doc>
+    </rule>
+    <rule name = "non-zero">
+      <doc>
+        The server MUST NOT use a zero value for delivery tags. Zero is reserved
+        for client use, meaning "all messages so far received".
+      </doc>
+    </rule>
+  </domain>
+
+  <domain name = "exchange-name" type = "shortstr" label = "exchange name">
+    <doc>
+      The exchange name is a client-selected string that identifies the exchange for
+      publish methods.
+    </doc>
+    <assert check = "length" value = "127" />
+    <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]*$" />
+  </domain>
+
+  <domain name = "method-id" type = "short" />
+
+  <domain name = "no-ack" type = "bit" label = "no acknowledgement needed">
+    <doc>
+      If this field is set the server does not expect acknowledgements for
+      messages. That is, when a message is delivered to the client the server
+      assumes the delivery will succeed and immediately dequeues it. This
+      functionality may increase performance but at the cost of reliability.
+      Messages can get lost if a client dies before they are delivered to the
+      application.
+    </doc>
+  </domain>
+
+  <domain name = "no-local" type = "bit" label = "do not deliver own messages">
+    <doc>
+      If the no-local field is set the server will not send messages to the connection that
+      published them.
+    </doc>
+  </domain>
+
+  <domain name = "no-wait" type = "bit" label = "do not send reply method">
+    <doc>
+      If set, the server will not respond to the method. The client should not wait
+      for a reply method. If the server could not complete the method it will raise a
+      channel or connection exception.
+    </doc>
+  </domain>
+
+  <domain name = "path" type = "shortstr">
+    <doc>
+      Unconstrained.
+    </doc>
+    <assert check = "notnull" />
+    <assert check = "length" value = "127" />
+  </domain>
+
+  <domain name = "peer-properties" type = "table">
+    <doc>
+      This table provides a set of peer properties, used for identification, debugging,
+      and general information.
+    </doc>
+  </domain>
+
+  <domain name = "queue-name" type = "shortstr" label = "queue name">
+    <doc>
+      The queue name identifies the queue within the vhost.  In methods where the queue
+      name may be blank, and that has no specific significance, this refers to the
+      'current' queue for the channel, meaning the last queue that the client declared
+      on the channel.  If the client did not declare a queue, and the method needs a
+      queue name, this will result in a 502 (syntax error) channel exception.
+    </doc>
+    <assert check = "length" value = "127" />
+    <assert check = "regexp" value = "^[a-zA-Z0-9-_.:]*$" />
+  </domain>
+
+  <domain name = "redelivered" type = "bit" label = "message is being redelivered">
+    <doc>
+      This indicates that the message has been previously delivered to this or
+      another client.
+    </doc>
+    <rule name = "implementation">
+      <doc>
+        The server SHOULD try to signal redelivered messages when it can. When
+        redelivering a message that was not successfully acknowledged, the server
+        SHOULD deliver it to the original client if possible.
+      </doc>
+      <doc type = "scenario">
+        Declare a shared queue and publish a message to the queue.  Consume the
+        message using explicit acknowledgements, but do not acknowledge the
+        message.  Close the connection, reconnect, and consume from the queue
+        again.  The message should arrive with the redelivered flag set.
+      </doc>
+    </rule>
+    <rule name = "hinting">
+      <doc>
+        The client MUST NOT rely on the redelivered field but should take it as a
+        hint that the message may already have been processed. A fully robust
+        client must be able to track duplicate received messages on non-transacted,
+        and locally-transacted channels.
+      </doc>
+    </rule>
+  </domain>
+
+  <domain name = "message-count" type = "long" label = "number of messages in queue">
+    <doc>
+      The number of messages in the queue, which will be zero for newly-declared
+      queues. This is the number of messages present in the queue, and committed
+      if the channel on which they were published is transacted, that are not
+      waiting acknowledgement.
+    </doc>
+  </domain>
+
+  <domain name = "reply-code" type = "short" label = "reply code from server">
+    <doc>
+      The reply code. The AMQ reply codes are defined as constants at the start
+      of this formal specification.
+    </doc>
+    <assert check = "notnull" />
+  </domain>
+
+  <domain name = "reply-text" type = "shortstr" label = "localised reply text">
+    <doc>
+      The localised reply text. This text can be logged as an aid to resolving
+      issues.
+    </doc>
+    <assert check = "notnull" />
+  </domain>
+
+  <!-- Elementary domains -->
+  <domain name = "bit"        type = "bit"       label = "single bit" />
+  <domain name = "octet"      type = "octet"     label = "single octet" />
+  <domain name = "short"      type = "short"     label = "16-bit integer" />
+  <domain name = "long"       type = "long"      label = "32-bit integer" />
+  <domain name = "longlong"   type = "longlong"  label = "64-bit integer" />
+  <domain name = "shortstr"   type = "shortstr"  label = "short string" />
+  <domain name = "longstr"    type = "longstr"   label = "long string" />
+  <domain name = "timestamp"  type = "timestamp" label = "64-bit timestamp" />
+  <domain name = "table"      type = "table"     label = "field table" />
+
+  <!-- ==  CONNECTION  ======================================================= -->
+
+  <class name = "connection" handler = "connection" index = "10" label = "work with socket connections">
+    <doc>
+      The connection class provides methods for a client to establish a network connection to
+      a server, and for both peers to operate the connection thereafter.
+    </doc>
+
+    <doc type = "grammar">
+      connection          = open-connection *use-connection close-connection
+      open-connection     = C:protocol-header
+                            S:START C:START-OK
+                            *challenge
+                            S:TUNE C:TUNE-OK
+                            C:OPEN S:OPEN-OK
+      challenge           = S:SECURE C:SECURE-OK
+      use-connection      = *channel
+      close-connection    = C:CLOSE S:CLOSE-OK
+                          / S:CLOSE C:CLOSE-OK
+    </doc>
+
+    <chassis name = "server" implement = "MUST" />
+    <chassis name = "client" implement = "MUST" />
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "start" synchronous = "1" index = "10" label = "start connection negotiation">
+      <doc>
+        This method starts the connection negotiation process by telling the client the
+        protocol version that the server proposes, along with a list of security mechanisms
+        which the client can use for authentication.
+      </doc>
+
+      <rule name = "protocol-name">
+        <doc>
+          If the server cannot support the protocol specified in the protocol header,
+          it MUST respond with a valid protocol header and then close the socket
+          connection.
+        </doc>
+        <doc type = "scenario">
+          The client sends a protocol header containing an invalid protocol name.
+          The server MUST respond by sending a valid protocol header and then closing
+          the connection.
+        </doc>
+      </rule>
+      <rule name = "server-support">
+        <doc>
+          The server MUST provide a protocol version that is lower than or equal to
+          that requested by the client in the protocol header.
+        </doc>
+        <doc type = "scenario">
+          The client requests a protocol version that is higher than any valid
+          implementation, e.g. 2.0.  The server must respond with a protocol header
+          indicating its supported protocol version, e.g. 1.0.
+        </doc>
+      </rule>
+      <rule name = "client-support">
+        <doc>
+          If the client cannot handle the protocol version suggested by the server
+          it MUST close the socket connection without sending any further data.
+        </doc>
+        <doc type = "scenario">
+          The server sends a protocol version that is lower than any valid
+          implementation, e.g. 0.1.  The client must respond by closing the
+          connection without sending any further data.
+        </doc>
+      </rule>
+
+      <chassis name = "client" implement = "MUST" />
+      <response name = "start-ok" />
+
+      <field name = "version-major" domain = "octet" label = "protocol major version">
+        <doc>
+          The major version number can take any value from 0 to 99 as defined in the
+          AMQP specification.
+        </doc>
+      </field>
+
+      <field name = "version-minor" domain = "octet" label = "protocol minor version">
+        <doc>
+          The minor version number can take any value from 0 to 99 as defined in the
+          AMQP specification.
+        </doc>
+      </field>
+
+      <field name = "server-properties" domain = "peer-properties" label = "server properties">
+        <rule name = "required-fields">
+          <doc>
+            The properties SHOULD contain at least these fields: "host", specifying the
+            server host name or address, "product", giving the name of the server product,
+            "version", giving the name of the server version, "platform", giving the name
+            of the operating system, "copyright", if appropriate, and "information", giving
+            other general information.
+          </doc>
+          <doc type = "scenario">
+            Client connects to server and inspects the server properties. It checks for
+            the presence of the required fields.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "mechanisms" domain = "longstr" label = "available security mechanisms">
+        <doc>
+          A list of the security mechanisms that the server supports, delimited by spaces.
+        </doc>
+        <assert check = "notnull" />
+      </field>
+
+      <field name = "locales" domain = "longstr" label = "available message locales">
+        <doc>
+          A list of the message locales that the server supports, delimited by spaces. The
+          locale defines the language in which the server will send reply texts.
+        </doc>
+        <rule name = "required-support">
+          <doc>
+            The server MUST support at least the en_US locale.
+          </doc>
+          <doc type = "scenario">
+            Client connects to server and inspects the locales field. It checks for
+            the presence of the required locale(s).
+          </doc>
+        </rule>
+        <assert check = "notnull" />
+      </field>
+    </method>
+
+    <method name = "start-ok" synchronous = "1" index = "11"
+      label = "select security mechanism and locale">
+      <doc>
+        This method selects a SASL security mechanism.
+      </doc>
+
+      <chassis name = "server" implement = "MUST" />
+
+      <field name = "client-properties" domain = "peer-properties" label = "client properties">
+        <rule name = "required-fields">
+          <!-- This rule is not testable from the client side -->
+          <doc>
+            The properties SHOULD contain at least these fields: "product", giving the name
+            of the client product, "version", giving the name of the client version, "platform",
+            giving the name of the operating system, "copyright", if appropriate, and
+            "information", giving other general information.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "mechanism" domain = "shortstr" label = "selected security mechanism">
+        <doc>
+          A single security mechanisms selected by the client, which must be one of those
+          specified by the server.
+        </doc>
+        <rule name = "security">
+          <doc>
+            The client SHOULD authenticate using the highest-level security profile it
+            can handle from the list provided by the server.
+          </doc>
+        </rule>
+        <rule name = "validity">
+          <doc>
+            If the mechanism field does not contain one of the security mechanisms
+            proposed by the server in the Start method, the server MUST close the
+            connection without sending any further data.
+          </doc>
+          <doc type = "scenario">
+            Client connects to server and sends an invalid security mechanism. The
+            server must respond by closing the connection (a socket close, with no
+            connection close negotiation).
+          </doc>
+        </rule>
+        <assert check = "notnull" />
+      </field>
+
+      <field name = "response" domain = "longstr" label = "security response data">
+        <doc>
+          A block of opaque data passed to the security mechanism. The contents of this
+          data are defined by the SASL security mechanism.
+        </doc>
+        <assert check = "notnull" />
+      </field>
+
+      <field name = "locale" domain = "shortstr" label = "selected message locale">
+        <doc>
+          A single message locale selected by the client, which must be one of those
+          specified by the server.
+        </doc>
+        <assert check = "notnull" />
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "secure" synchronous = "1" index = "20" label = "security mechanism challenge">
+      <doc>
+        The SASL protocol works by exchanging challenges and responses until both peers have
+        received sufficient information to authenticate each other. This method challenges
+        the client to provide more information.
+      </doc>
+
+      <chassis name = "client" implement = "MUST" />
+      <response name = "secure-ok" />
+
+      <field name = "challenge" domain = "longstr" label = "security challenge data">
+        <doc>
+          Challenge information, a block of opaque binary data passed to the security
+          mechanism.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "secure-ok" synchronous = "1" index = "21" label = "security mechanism response">
+      <doc>
+        This method attempts to authenticate, passing a block of SASL data for the security
+        mechanism at the server side.
+      </doc>
+
+      <chassis name = "server" implement = "MUST" />
+
+      <field name = "response" domain = "longstr" label = "security response data">
+        <doc>
+          A block of opaque data passed to the security mechanism. The contents of this
+          data are defined by the SASL security mechanism.
+        </doc>
+        <assert check = "notnull" />
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "tune" synchronous = "1" index = "30"
+      label = "propose connection tuning parameters">
+      <doc>
+        This method proposes a set of connection configuration values to the client. The
+        client can accept and/or adjust these.
+      </doc>
+
+      <chassis name = "client" implement = "MUST" />
+
+      <response name = "tune-ok" />
+
+      <field name = "channel-max" domain = "short" label = "proposed maximum channels">
+        <doc>
+          Specifies highest channel number that the server permits.  Usable channel numbers
+          are in the range 1..channel-max.  Zero indicates no specified limit.
+        </doc>
+      </field>
+
+      <field name = "frame-max" domain = "long" label = "proposed maximum frame size">
+        <doc>
+          The largest frame size that the server proposes for the connection, including
+          frame header and end-byte.  The client can negotiate a lower value. Zero means
+          that the server does not impose any specific limit but may reject very large
+          frames if it cannot allocate resources for them.
+        </doc>
+        <rule name = "minimum">
+          <doc>
+            Until the frame-max has been negotiated, both peers MUST accept frames of up
+            to frame-min-size octets large, and the minimum negotiated value for frame-max
+            is also frame-min-size.
+          </doc>
+          <doc type = "scenario">
+            Client connects to server and sends a large properties field, creating a frame
+            of frame-min-size octets.  The server must accept this frame.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "heartbeat" domain = "short" label = "desired heartbeat delay">
+        <doc>
+          The delay, in seconds, of the connection heartbeat that the server wants.
+          Zero means the server does not want a heartbeat.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "tune-ok" synchronous = "1" index = "31"
+      label = "negotiate connection tuning parameters">
+      <doc>
+        This method sends the client's connection tuning parameters to the server.
+        Certain fields are negotiated, others provide capability information.
+      </doc>
+
+      <chassis name = "server" implement = "MUST" />
+
+      <field name = "channel-max" domain = "short" label = "negotiated maximum channels">
+        <doc>
+          The maximum total number of channels that the client will use per connection.
+        </doc>
+        <rule name = "upper-limit">
+          <doc>
+            If the client specifies a channel max that is higher than the value provided
+            by the server, the server MUST close the connection without attempting a
+            negotiated close.  The server may report the error in some fashion to assist
+            implementors.
+          </doc>
+        </rule>
+        <assert check = "notnull" />
+        <assert check = "le" method = "tune" field = "channel-max" />
+      </field>
+
+      <field name = "frame-max" domain = "long" label = "negotiated maximum frame size">
+        <doc>
+          The largest frame size that the client and server will use for the connection.
+          Zero means that the client does not impose any specific limit but may reject
+          very large frames if it cannot allocate resources for them. Note that the
+          frame-max limit applies principally to content frames, where large contents can
+          be broken into frames of arbitrary size.
+        </doc>
+        <rule name = "minimum">
+          <doc>
+            Until the frame-max has been negotiated, both peers MUST accept frames of up
+            to frame-min-size octets large, and the minimum negotiated value for frame-max
+            is also frame-min-size.
+          </doc>
+        </rule>
+        <rule name = "upper-limit">
+          <doc>
+            If the client specifies a frame max that is higher than the value provided
+            by the server, the server MUST close the connection without attempting a
+            negotiated close. The server may report the error in some fashion to assist
+            implementors.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "heartbeat" domain = "short" label = "desired heartbeat delay">
+        <doc>
+          The delay, in seconds, of the connection heartbeat that the client wants. Zero
+          means the client does not want a heartbeat.
+        </doc>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "open" synchronous = "1" index = "40" label = "open connection to virtual host">
+      <doc>
+        This method opens a connection to a virtual host, which is a collection of
+        resources, and acts to separate multiple application domains within a server.
+        The server may apply arbitrary limits per virtual host, such as the number
+        of each type of entity that may be used, per connection and/or in total.
+      </doc>
+
+      <chassis name = "server" implement = "MUST" />
+      <response name = "open-ok" />
+
+      <field name = "virtual-host" domain = "path" label = "virtual host name">
+        <doc>
+          The name of the virtual host to work with.
+        </doc>
+        <rule name = "separation">
+          <doc>
+            If the server supports multiple virtual hosts, it MUST enforce a full
+            separation of exchanges, queues, and all associated entities per virtual
+            host. An application, connected to a specific virtual host, MUST NOT be able
+            to access resources of another virtual host.
+          </doc>
+        </rule>
+        <rule name = "security">
+          <doc>
+            The server SHOULD verify that the client has permission to access the
+            specified virtual host.
+          </doc>
+        </rule>
+      </field>
+      <!-- Deprecated: "capabilities", must be zero -->
+      <field name = "reserved-1" type = "shortstr" reserved = "1" />
+      <!-- Deprecated: "insist", must be zero -->
+      <field name = "reserved-2" type = "bit" reserved = "1" />
+    </method>
+
+    <method name = "open-ok" synchronous = "1" index = "41" label = "signal that connection is ready">
+      <doc>
+        This method signals to the client that the connection is ready for use.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+      <!-- Deprecated: "known-hosts", must be zero -->
+      <field name = "reserved-1" type = "shortstr" reserved = "1" />
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "close" synchronous = "1" index = "50" label = "request a connection close">
+      <doc>
+        This method indicates that the sender wants to close the connection. This may be
+        due to internal conditions (e.g. a forced shut-down) or due to an error handling
+        a specific method, i.e. an exception. When a close is due to an exception, the
+        sender provides the class and method id of the method which caused the exception.
+      </doc>
+      <rule name = "stability">
+        <doc>
+          After sending this method, any received methods except Close and Close-OK MUST
+          be discarded.  The response to receiving a Close after sending Close must be to
+          send Close-Ok.
+        </doc>
+      </rule>
+
+      <chassis name = "client" implement = "MUST" />
+      <chassis name = "server" implement = "MUST" />
+      <response name = "close-ok" />
+
+      <field name = "reply-code" domain = "reply-code" />
+      <field name = "reply-text" domain = "reply-text" />
+
+      <field name = "class-id" domain = "class-id" label = "failing method class">
+        <doc>
+          When the close is provoked by a method exception, this is the class of the
+          method.
+        </doc>
+      </field>
+
+      <field name = "method-id" domain = "method-id" label = "failing method ID">
+        <doc>
+          When the close is provoked by a method exception, this is the ID of the method.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "close-ok" synchronous = "1" index = "51" label = "confirm a connection close">
+      <doc>
+        This method confirms a Connection.Close method and tells the recipient that it is
+        safe to release resources for the connection and close the socket.
+      </doc>
+      <rule name = "reporting">
+        <doc>
+          A peer that detects a socket closure without having received a Close-Ok
+          handshake method SHOULD log the error.
+        </doc>
+      </rule>
+      <chassis name = "client" implement = "MUST" />
+      <chassis name = "server" implement = "MUST" />
+    </method>
+  </class>
+
+  <!-- ==  CHANNEL  ========================================================== -->
+
+  <class name = "channel" handler = "channel" index = "20" label = "work with channels">
+    <doc>
+      The channel class provides methods for a client to establish a channel to a
+      server and for both peers to operate the channel thereafter.
+    </doc>
+
+    <doc type = "grammar">
+      channel             = open-channel *use-channel close-channel
+      open-channel        = C:OPEN S:OPEN-OK
+      use-channel         = C:FLOW S:FLOW-OK
+                          / S:FLOW C:FLOW-OK
+                          / functional-class
+      close-channel       = C:CLOSE S:CLOSE-OK
+                          / S:CLOSE C:CLOSE-OK
+    </doc>
+
+    <chassis name = "server" implement = "MUST" />
+    <chassis name = "client" implement = "MUST" />
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "open" synchronous = "1" index = "10" label = "open a channel for use">
+      <doc>
+        This method opens a channel to the server.
+      </doc>
+      <rule name = "state" on-failure = "channel-error">
+        <doc>
+          The client MUST NOT use this method on an already-opened channel.
+        </doc>
+        <doc type = "scenario">
+          Client opens a channel and then reopens the same channel.
+        </doc>
+      </rule>
+      <chassis name = "server" implement = "MUST" />
+      <response name = "open-ok" />
+      <!-- Deprecated: "out-of-band", must be zero -->
+      <field name = "reserved-1" type = "shortstr" reserved = "1" />
+    </method>
+
+    <method name = "open-ok" synchronous = "1" index = "11" label = "signal that the channel is ready">
+      <doc>
+        This method signals to the client that the channel is ready for use.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+      <!-- Deprecated: "channel-id", must be zero -->
+      <field name = "reserved-1" type = "longstr" reserved = "1" />
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "flow" synchronous = "1" index = "20" label = "enable/disable flow from peer">
+      <doc>
+        This method asks the peer to pause or restart the flow of content data sent by
+        a consumer. This is a simple flow-control mechanism that a peer can use to avoid
+        overflowing its queues or otherwise finding itself receiving more messages than
+        it can process. Note that this method is not intended for window control. It does
+        not affect contents returned by Basic.Get-Ok methods.
+      </doc>
+
+      <rule name = "initial-state">
+        <doc>
+          When a new channel is opened, it is active (flow is active). Some applications
+          assume that channels are inactive until started. To emulate this behaviour a
+          client MAY open the channel, then pause it.
+        </doc>
+      </rule>
+
+      <rule name = "bidirectional">
+        <doc>
+          When sending content frames, a peer SHOULD monitor the channel for incoming
+          methods and respond to a Channel.Flow as rapidly as possible.
+        </doc>
+      </rule>
+
+      <rule name = "throttling">
+        <doc>
+          A peer MAY use the Channel.Flow method to throttle incoming content data for
+          internal reasons, for example, when exchanging data over a slower connection.
+        </doc>
+      </rule>
+
+      <rule name = "expected-behaviour">
+        <doc>
+          The peer that requests a Channel.Flow method MAY disconnect and/or ban a peer
+          that does not respect the request.  This is to prevent badly-behaved clients
+          from overwhelming a server.
+        </doc>
+      </rule>
+
+      <chassis name = "server" implement = "MUST" />
+      <chassis name = "client" implement = "MUST" />
+
+      <response name = "flow-ok" />
+
+      <field name = "active" domain = "bit" label = "start/stop content frames">
+        <doc>
+          If 1, the peer starts sending content frames. If 0, the peer stops sending
+          content frames.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "flow-ok" index = "21" label = "confirm a flow method">
+      <doc>
+        Confirms to the peer that a flow command was received and processed.
+      </doc>
+      <chassis name = "server" implement = "MUST" />
+      <chassis name = "client" implement = "MUST" />
+      <field name = "active" domain = "bit" label = "current flow setting">
+        <doc>
+          Confirms the setting of the processed flow method: 1 means the peer will start
+          sending or continue to send content frames; 0 means it will not.
+        </doc>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "close" synchronous = "1" index = "40" label = "request a channel close">
+      <doc>
+        This method indicates that the sender wants to close the channel. This may be due to
+        internal conditions (e.g. a forced shut-down) or due to an error handling a specific
+        method, i.e. an exception. When a close is due to an exception, the sender provides
+        the class and method id of the method which caused the exception.
+      </doc>
+      <rule name = "stability">
+        <doc>
+          After sending this method, any received methods except Close and Close-OK MUST
+          be discarded.  The response to receiving a Close after sending Close must be to
+          send Close-Ok.
+        </doc>
+      </rule>
+
+      <chassis name = "client" implement = "MUST" />
+      <chassis name = "server" implement = "MUST" />
+      <response name = "close-ok" />
+
+      <field name = "reply-code" domain = "reply-code" />
+      <field name = "reply-text" domain = "reply-text" />
+
+      <field name = "class-id" domain = "class-id" label = "failing method class">
+        <doc>
+          When the close is provoked by a method exception, this is the class of the
+          method.
+        </doc>
+      </field>
+
+      <field name = "method-id" domain = "method-id" label = "failing method ID">
+        <doc>
+          When the close is provoked by a method exception, this is the ID of the method.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "close-ok" synchronous = "1" index = "41" label = "confirm a channel close">
+      <doc>
+        This method confirms a Channel.Close method and tells the recipient that it is safe
+        to release resources for the channel.
+      </doc>
+      <rule name = "reporting">
+        <doc>
+          A peer that detects a socket closure without having received a Channel.Close-Ok
+          handshake method SHOULD log the error.
+        </doc>
+      </rule>
+      <chassis name = "client" implement = "MUST" />
+      <chassis name = "server" implement = "MUST" />
+    </method>
+  </class>
+
+  <!-- ==  EXCHANGE  ========================================================= -->
+
+  <class name = "exchange" handler = "channel" index = "40" label = "work with exchanges">
+    <doc>
+      Exchanges match and distribute messages across queues. Exchanges can be configured in
+      the server or declared at runtime.
+    </doc>
+
+    <doc type = "grammar">
+      exchange            = C:DECLARE  S:DECLARE-OK
+                          / C:DELETE   S:DELETE-OK
+    </doc>
+
+    <chassis name = "server" implement = "MUST" />
+    <chassis name = "client" implement = "MUST" />
+
+    <rule name = "required-types">
+      <doc>
+        The server MUST implement these standard exchange types: fanout, direct.
+      </doc>
+      <doc type = "scenario">
+        Client attempts to declare an exchange with each of these standard types.
+      </doc>
+    </rule>
+    <rule name = "recommended-types">
+      <doc>
+        The server SHOULD implement these standard exchange types: topic, headers.
+      </doc>
+      <doc type = "scenario">
+        Client attempts to declare an exchange with each of these standard types.
+      </doc>
+    </rule>
+    <rule name = "required-instances">
+      <doc>
+        The server MUST, in each virtual host, pre-declare an exchange instance
+        for each standard exchange type that it implements, where the name of the
+        exchange instance, if defined, is "amq." followed by the exchange type name.
+      </doc>
+      <doc>
+        The server MUST, in each virtual host, pre-declare at least two direct
+        exchange instances: one named "amq.direct", the other with no public name
+        that serves as a default  exchange for Publish methods.
+      </doc>
+      <doc type = "scenario">
+        Client declares a temporary queue and attempts to bind to each required
+        exchange instance ("amq.fanout", "amq.direct", "amq.topic", and "amq.headers"
+        if those types are defined).
+      </doc>
+    </rule>
+    <rule name = "default-exchange">
+      <doc>
+        The server MUST pre-declare a direct exchange with no public name to act as
+        the default exchange for content Publish methods and for default queue bindings.
+      </doc>
+      <doc type = "scenario">
+        Client checks that the default exchange is active by specifying a queue
+        binding with no exchange name, and publishing a message with a suitable
+        routing key but without specifying the exchange name, then ensuring that
+        the message arrives in the queue correctly.
+      </doc>
+    </rule>
+    <rule name = "default-access">
+      <doc>
+        The server MUST NOT allow clients to access the default exchange except
+        by specifying an empty exchange name in the Queue.Bind and content Publish
+        methods.
+      </doc>
+    </rule>
+    <rule name = "extensions">
+      <doc>
+        The server MAY implement other exchange types as wanted.
+      </doc>
+    </rule>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "declare" synchronous = "1" index = "10" label = "verify exchange exists, create if needed">
+      <doc>
+        This method creates an exchange if it does not already exist, and if the exchange
+        exists, verifies that it is of the correct and expected class.
+      </doc>
+      <rule name = "minimum">
+        <doc>
+          The server SHOULD support a minimum of 16 exchanges per virtual host and
+          ideally, impose no limit except as defined by available resources.
+        </doc>
+        <doc type = "scenario">
+          The client declares as many exchanges as it can until the server reports
+          an error; the number of exchanges successfully declared must be at least
+          sixteen.
+        </doc>
+      </rule>
+
+      <chassis name = "server" implement = "MUST" />
+      <response name = "declare-ok" />
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "exchange" domain = "exchange-name">
+        <rule name = "reserved" on-failure = "access-refused">
+          <doc>
+            Exchange names starting with "amq." are reserved for pre-declared and
+            standardised exchanges. The client MAY declare an exchange starting with
+            "amq." if the passive option is set, or the exchange already exists.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to declare a non-existing exchange starting with
+            "amq." and with the passive option set to zero.
+          </doc>
+        </rule>
+        <rule name = "syntax" on-failure = "precondition-failed">
+          <doc>
+            The exchange name consists of a non-empty sequence of these characters:
+            letters, digits, hyphen, underscore, period, or colon.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to declare an exchange with an illegal name.
+          </doc>
+        </rule>
+        <assert check = "notnull" />
+      </field>
+
+      <field name = "type" domain = "shortstr" label = "exchange type">
+        <doc>
+          Each exchange belongs to one of a set of exchange types implemented by the
+          server. The exchange types define the functionality of the exchange - i.e. how
+          messages are routed through it. It is not valid or meaningful to attempt to
+          change the type of an existing exchange.
+        </doc>
+        <rule name = "typed" on-failure = "not-allowed">
+          <doc>
+            Exchanges cannot be redeclared with different types.  The client MUST not
+            attempt to redeclare an existing exchange with a different type than used
+            in the original Exchange.Declare method.
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+        <rule name = "support" on-failure = "command-invalid">
+          <doc>
+            The client MUST NOT attempt to declare an exchange with a type that the
+            server does not support.
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "passive" domain = "bit" label = "do not create exchange">
+        <doc>
+          If set, the server will reply with Declare-Ok if the exchange already
+          exists with the same name, and raise an error if not.  The client can
+          use this to check whether an exchange exists without modifying the
+          server state. When set, all other method fields except name and no-wait
+          are ignored.  A declare with both passive and no-wait has no effect.
+          Arguments are compared for semantic equivalence.
+        </doc>
+        <rule name = "not-found">
+          <doc>
+            If set, and the exchange does not already exist, the server MUST
+            raise a channel exception with reply code 404 (not found).
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+        <rule name = "equivalent">
+          <doc>
+            If not set and the exchange exists, the server MUST check that the
+            existing exchange has the same values for type, durable, and arguments
+            fields.  The server MUST respond with Declare-Ok if the requested
+            exchange matches these fields, and MUST raise a channel exception if
+            not.
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "durable" domain = "bit" label = "request a durable exchange">
+        <doc>
+          If set when creating a new exchange, the exchange will be marked as durable.
+          Durable exchanges remain active when a server restarts. Non-durable exchanges
+          (transient exchanges) are purged if/when a server restarts.
+        </doc>
+        <rule name = "support">
+          <doc>
+            The server MUST support both durable and transient exchanges.
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+      </field>
+
+      <!-- Deprecated: "auto-delete", must be zero -->
+      <field name = "reserved-2" type = "bit" reserved = "1" />
+      <!-- Deprecated: "internal", must be zero -->
+      <field name = "reserved-3" type = "bit" reserved = "1" />
+      <field name = "no-wait" domain = "no-wait" />
+
+      <field name = "arguments" domain = "table" label = "arguments for declaration">
+        <doc>
+          A set of arguments for the declaration. The syntax and semantics of these
+          arguments depends on the server implementation.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "declare-ok" synchronous = "1" index = "11" label = "confirm exchange declaration">
+      <doc>
+        This method confirms a Declare method and confirms the name of the exchange,
+        essential for automatically-named exchanges.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "delete" synchronous = "1" index = "20" label = "delete an exchange">
+      <doc>
+        This method deletes an exchange. When an exchange is deleted all queue bindings on
+        the exchange are cancelled.
+      </doc>
+
+      <chassis name = "server" implement = "MUST" />
+      <response name = "delete-ok" />
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "exchange" domain = "exchange-name">
+        <rule name = "exists" on-failure = "not-found">
+          <doc>
+            The client MUST NOT attempt to delete an exchange that does not exist.
+          </doc>
+        </rule>
+        <assert check = "notnull" />
+      </field>
+
+      <field name = "if-unused" domain = "bit" label = "delete only if unused">
+        <doc>
+          If set, the server will only delete the exchange if it has no queue bindings. If
+          the exchange has queue bindings the server does not delete it but raises a
+          channel exception instead.
+        </doc>
+        <rule name = "in-use" on-failure = "precondition-failed">
+          <doc>
+            The server MUST NOT delete an exchange that has bindings on it, if the if-unused
+            field is true.
+          </doc>
+          <doc type = "scenario">
+            The client declares an exchange, binds a queue to it, then tries to delete it
+            setting if-unused to true.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "no-wait" domain = "no-wait" />
+    </method>
+
+    <method name = "delete-ok" synchronous = "1" index = "21"
+      label = "confirm deletion of an exchange">
+      <doc>This method confirms the deletion of an exchange.</doc>
+      <chassis name = "client" implement = "MUST" />
+    </method>
+  </class>
+
+  <!-- ==  QUEUE  ============================================================ -->
+
+  <class name = "queue" handler = "channel" index = "50" label = "work with queues">
+    <doc>
+      Queues store and forward messages. Queues can be configured in the server or created at
+      runtime. Queues must be attached to at least one exchange in order to receive messages
+      from publishers.
+    </doc>
+
+    <doc type = "grammar">
+      queue               = C:DECLARE  S:DECLARE-OK
+                          / C:BIND     S:BIND-OK
+                          / C:UNBIND   S:UNBIND-OK
+                          / C:PURGE    S:PURGE-OK
+                          / C:DELETE   S:DELETE-OK
+    </doc>
+
+    <chassis name = "server" implement = "MUST" />
+    <chassis name = "client" implement = "MUST" />
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "declare" synchronous = "1" index = "10" label = "declare queue, create if needed">
+      <doc>
+        This method creates or checks a queue. When creating a new queue the client can
+        specify various properties that control the durability of the queue and its
+        contents, and the level of sharing for the queue.
+      </doc>
+
+      <rule name = "default-binding">
+        <doc>
+          The server MUST create a default binding for a newly-declared queue to the
+          default exchange, which is an exchange of type 'direct' and use the queue
+          name as the routing key.
+        </doc>
+        <doc type = "scenario">
+          Client declares a new queue, and then without explicitly binding it to an
+          exchange, attempts to send a message through the default exchange binding,
+          i.e. publish a message to the empty exchange, with the queue name as routing
+          key.
+        </doc>
+      </rule>
+
+      <rule name = "minimum-queues">
+        <doc>
+          The server SHOULD support a minimum of 256 queues per virtual host and ideally,
+          impose no limit except as defined by available resources.
+        </doc>
+        <doc type = "scenario">
+          Client attempts to declare as many queues as it can until the server reports
+          an error.  The resulting count must at least be 256.
+        </doc>
+      </rule>
+
+      <chassis name = "server" implement = "MUST" />
+      <response name = "declare-ok" />
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "queue" domain = "queue-name">
+        <rule name = "default-name">
+          <doc>
+            The queue name MAY be empty, in which case the server MUST create a new
+            queue with a unique generated name and return this to the client in the
+            Declare-Ok method.
+          </doc>
+          <doc type = "scenario">
+            Client attempts to declare several queues with an empty name. The client then
+            verifies that the server-assigned names are unique and different.
+          </doc>
+        </rule>
+        <rule name = "reserved" on-failure = "access-refused">
+          <doc>
+            Queue names starting with "amq." are reserved for pre-declared and
+            standardised queues. The client MAY declare a queue starting with
+            "amq." if the passive option is set, or the queue already exists.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to declare a non-existing queue starting with
+            "amq." and with the passive option set to zero.
+          </doc>
+        </rule>
+        <rule name = "syntax" on-failure = "precondition-failed">
+          <doc>
+            The queue name can be empty, or a sequence of these characters:
+            letters, digits, hyphen, underscore, period, or colon.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to declare a queue with an illegal name.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "passive" domain = "bit" label = "do not create queue">
+        <doc>
+          If set, the server will reply with Declare-Ok if the queue already
+          exists with the same name, and raise an error if not.  The client can
+          use this to check whether a queue exists without modifying the
+          server state.  When set, all other method fields except name and no-wait
+          are ignored.  A declare with both passive and no-wait has no effect.
+          Arguments are compared for semantic equivalence.
+        </doc>
+        <rule name = "passive" on-failure = "not-found">
+          <doc>
+            The client MAY ask the server to assert that a queue exists without
+            creating the queue if not.  If the queue does not exist, the server
+            treats this as a failure.
+          </doc>
+          <doc type = "scenario">
+            Client declares an existing queue with the passive option and expects
+            the server to respond with a declare-ok. Client then attempts to declare
+            a non-existent queue with the passive option, and the server must close
+            the channel with the correct reply-code.
+          </doc>
+        </rule>
+        <rule name = "equivalent">
+          <doc>
+            If not set and the queue exists, the server MUST check that the
+            existing queue has the same values for durable, exclusive, auto-delete,
+            and arguments fields.  The server MUST respond with Declare-Ok if the
+            requested queue matches these fields, and MUST raise a channel exception
+            if not.
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "durable" domain = "bit" label = "request a durable queue">
+        <doc>
+          If set when creating a new queue, the queue will be marked as durable. Durable
+          queues remain active when a server restarts. Non-durable queues (transient
+          queues) are purged if/when a server restarts. Note that durable queues do not
+          necessarily hold persistent messages, although it does not make sense to send
+          persistent messages to a transient queue.
+        </doc>
+
+        <rule name = "persistence">
+          <doc>The server MUST recreate the durable queue after a restart.</doc>
+
+          <doc type = "scenario">
+            Client declares a durable queue. The server is then restarted. The client
+            then attempts to send a message to the queue. The message should be successfully
+            delivered.
+          </doc>
+        </rule>
+
+        <rule name = "types">
+          <doc>The server MUST support both durable and transient queues.</doc>
+          <doc type = "scenario">
+            A client declares two named queues, one durable and one transient.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "exclusive" domain = "bit" label = "request an exclusive queue">
+        <doc>
+          Exclusive queues may only be accessed by the current connection, and are
+          deleted when that connection closes.  Passive declaration of an exclusive
+          queue by other connections are not allowed.
+        </doc>
+
+        <rule name = "types">
+          <doc>
+            The server MUST support both exclusive (private) and non-exclusive (shared)
+            queues.
+          </doc>
+          <doc type = "scenario">
+            A client declares two named queues, one exclusive and one non-exclusive.
+          </doc>
+        </rule>
+
+        <rule name = "exclusive" on-failure = "resource-locked">
+          <doc>
+            The client MAY NOT attempt to use a queue that was declared as exclusive
+            by another still-open connection.
+          </doc>
+          <doc type = "scenario">
+            One client declares an exclusive queue. A second client on a different
+            connection attempts to declare, bind, consume, purge, delete, or declare
+            a queue of the same name.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "auto-delete" domain = "bit" label = "auto-delete queue when unused">
+        <doc>
+          If set, the queue is deleted when all consumers have finished using it.  The last
+          consumer can be cancelled either explicitly or because its channel is closed. If
+          there was no consumer ever on the queue, it won't be deleted.  Applications can
+          explicitly delete auto-delete queues using the Delete method as normal.
+        </doc>
+
+        <rule name = "pre-existence">
+          <doc>
+            The server MUST ignore the auto-delete field if the queue already exists.
+          </doc>
+          <doc type = "scenario">
+            Client declares two named queues, one as auto-delete and one explicit-delete.
+            Client then attempts to declare the two queues using the same names again,
+            but reversing the value of the auto-delete field in each case. Verify that the
+            queues still exist with the original auto-delete flag values.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "no-wait" domain = "no-wait" />
+
+      <field name = "arguments" domain = "table" label = "arguments for declaration">
+        <doc>
+          A set of arguments for the declaration. The syntax and semantics of these
+          arguments depends on the server implementation.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "declare-ok" synchronous = "1" index = "11" label = "confirms a queue definition">
+      <doc>
+        This method confirms a Declare method and confirms the name of the queue, essential
+        for automatically-named queues.
+      </doc>
+
+      <chassis name = "client" implement = "MUST" />
+
+      <field name = "queue" domain = "queue-name">
+        <doc>
+          Reports the name of the queue. If the server generated a queue name, this field
+          contains that name.
+        </doc>
+        <assert check = "notnull" />
+      </field>
+
+      <field name = "message-count" domain = "message-count" />
+
+      <field name = "consumer-count" domain = "long" label = "number of consumers">
+        <doc>
+          Reports the number of active consumers for the queue. Note that consumers can
+          suspend activity (Channel.Flow) in which case they do not appear in this count.
+        </doc>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "bind" synchronous = "1" index = "20" label = "bind queue to an exchange">
+      <doc>
+        This method binds a queue to an exchange. Until a queue is bound it will not
+        receive any messages. In a classic messaging model, store-and-forward queues
+        are bound to a direct exchange and subscription queues are bound to a topic
+        exchange.
+      </doc>
+
+      <rule name = "duplicates">
+        <doc>
+          A server MUST allow ignore duplicate bindings - that is, two or more bind
+          methods for a specific queue, with identical arguments - without treating these
+          as an error.
+        </doc>
+        <doc type = "scenario">
+          A client binds a named queue to an exchange. The client then repeats the bind
+          (with identical arguments).
+        </doc>
+      </rule>
+
+      <rule name = "unique">
+        <doc>
+          A server MUST not deliver the same message more than once to a queue, even if
+          the queue has multiple bindings that match the message.
+        </doc>
+        <doc type = "scenario">
+          A client declares a named queue and binds it using multiple bindings to the
+          amq.topic exchange. The client then publishes a message that matches all its
+          bindings.
+        </doc>
+      </rule>
+
+      <rule name = "transient-exchange">
+        <doc>
+          The server MUST allow a durable queue to bind to a transient exchange.
+        </doc>
+        <doc type = "scenario">
+          A client declares a transient exchange. The client then declares a named durable
+          queue and then attempts to bind the transient exchange to the durable queue.
+        </doc>
+      </rule>
+
+      <rule name = "durable-exchange">
+        <doc>
+          Bindings of durable queues to durable exchanges are automatically durable
+          and the server MUST restore such bindings after a server restart.
+        </doc>
+        <doc type = "scenario">
+          A server declares a named durable queue and binds it to a durable exchange. The
+          server is restarted. The client then attempts to use the queue/exchange combination.
+        </doc>
+      </rule>
+
+      <rule name = "binding-count">
+        <doc>
+          The server SHOULD support at least 4 bindings per queue, and ideally, impose no
+          limit except as defined by available resources.
+        </doc>
+        <doc type = "scenario">
+          A client declares a named queue and attempts to bind it to 4 different
+          exchanges.
+        </doc>
+      </rule>
+
+      <chassis name = "server" implement = "MUST" />
+
+      <response name = "bind-ok" />
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "queue" domain = "queue-name">
+        <doc>Specifies the name of the queue to bind.</doc>
+        <rule name = "queue-known" on-failure = "not-found">
+          <doc>
+            The client MUST either specify a queue name or have previously declared a
+            queue on the same channel
+          </doc>
+          <doc type = "scenario">
+            The client opens a channel and attempts to bind an unnamed queue.
+          </doc>
+        </rule>
+        <rule name = "must-exist" on-failure = "not-found">
+          <doc>
+            The client MUST NOT attempt to bind a queue that does not exist.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to bind a non-existent queue.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "exchange" domain = "exchange-name" label = "name of the exchange to bind to">
+        <rule name = "exchange-existence" on-failure = "not-found">
+          <doc>
+            A client MUST NOT be allowed to bind a queue to a non-existent exchange.
+          </doc>
+          <doc type = "scenario">
+            A client attempts to bind an named queue to a undeclared exchange.
+          </doc>
+        </rule>
+        <rule name = "default-exchange">
+          <doc>
+            The server MUST accept a blank exchange name to mean the default exchange.
+          </doc>
+          <doc type = "scenario">
+            The client declares a queue and binds it to a blank exchange name.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "routing-key" domain = "shortstr" label = "message routing key">
+        <doc>
+          Specifies the routing key for the binding. The routing key is used for routing
+          messages depending on the exchange configuration. Not all exchanges use a
+          routing key - refer to the specific exchange documentation.  If the queue name
+          is empty, the server uses the last queue declared on the channel.  If the
+          routing key is also empty, the server uses this queue name for the routing
+          key as well.  If the queue name is provided but the routing key is empty, the
+          server does the binding with that empty routing key.  The meaning of empty
+          routing keys depends on the exchange implementation.
+        </doc>
+        <rule name = "direct-exchange-key-matching">
+          <doc>
+            If a message queue binds to a direct exchange using routing key K and a
+            publisher sends the exchange a message with routing key R, then the message
+            MUST be passed to the message queue if K = R.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "no-wait" domain = "no-wait" />
+
+      <field name = "arguments" domain = "table" label = "arguments for binding">
+        <doc>
+          A set of arguments for the binding. The syntax and semantics of these arguments
+          depends on the exchange class.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "bind-ok" synchronous = "1" index = "21" label = "confirm bind successful">
+      <doc>This method confirms that the bind was successful.</doc>
+
+      <chassis name = "client" implement = "MUST" />
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "unbind" synchronous = "1" index = "50" label = "unbind a queue from an exchange">
+      <doc>This method unbinds a queue from an exchange.</doc>
+      <rule name = "01">
+        <doc>If a unbind fails, the server MUST raise a connection exception.</doc>
+      </rule>
+      <chassis name="server" implement="MUST"/>
+      <response name="unbind-ok"/>
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "queue" domain = "queue-name">
+        <doc>Specifies the name of the queue to unbind.</doc>
+        <rule name = "queue-known" on-failure = "not-found">
+          <doc>
+            The client MUST either specify a queue name or have previously declared a
+            queue on the same channel
+          </doc>
+          <doc type = "scenario">
+            The client opens a channel and attempts to unbind an unnamed queue.
+          </doc>
+        </rule>
+        <rule name = "must-exist" on-failure = "not-found">
+          <doc>
+            The client MUST NOT attempt to unbind a queue that does not exist.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to unbind a non-existent queue.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "exchange" domain = "exchange-name">
+        <doc>The name of the exchange to unbind from.</doc>
+        <rule name = "must-exist" on-failure = "not-found">
+          <doc>
+            The client MUST NOT attempt to unbind a queue from an exchange that
+            does not exist.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to unbind a queue from a non-existent exchange.
+          </doc>
+        </rule>
+        <rule name = "default-exchange">
+          <doc>
+            The server MUST accept a blank exchange name to mean the default exchange.
+          </doc>
+          <doc type = "scenario">
+            The client declares a queue and binds it to a blank exchange name.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "routing-key" domain = "shortstr" label = "routing key of binding">
+        <doc>Specifies the routing key of the binding to unbind.</doc>
+      </field>
+
+      <field name = "arguments" domain = "table" label = "arguments of binding">
+        <doc>Specifies the arguments of the binding to unbind.</doc>
+      </field>
+    </method>
+
+    <method name = "unbind-ok" synchronous = "1" index = "51" label = "confirm unbind successful">
+      <doc>This method confirms that the unbind was successful.</doc>
+      <chassis name = "client" implement = "MUST"/>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "purge" synchronous = "1" index = "30" label = "purge a queue">
+      <doc>
+        This method removes all messages from a queue which are not awaiting
+        acknowledgment.
+      </doc>
+
+      <rule name = "02">
+        <doc>
+          The server MUST NOT purge messages that have already been sent to a client
+          but not yet acknowledged.
+        </doc>
+      </rule>
+
+      <rule name = "03">
+        <doc>
+          The server MAY implement a purge queue or log that allows system administrators
+          to recover accidentally-purged messages. The server SHOULD NOT keep purged
+          messages in the same storage spaces as the live messages since the volumes of
+          purged messages may get very large.
+        </doc>
+      </rule>
+
+      <chassis name = "server" implement = "MUST" />
+
+      <response name = "purge-ok" />
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "queue" domain = "queue-name">
+        <doc>Specifies the name of the queue to purge.</doc>
+        <rule name = "queue-known" on-failure = "not-found">
+          <doc>
+            The client MUST either specify a queue name or have previously declared a
+            queue on the same channel
+          </doc>
+          <doc type = "scenario">
+            The client opens a channel and attempts to purge an unnamed queue.
+          </doc>
+        </rule>
+        <rule name = "must-exist" on-failure = "not-found">
+          <doc>
+            The client MUST NOT attempt to purge a queue that does not exist.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to purge a non-existent queue.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "no-wait" domain = "no-wait" />
+    </method>
+
+    <method name = "purge-ok" synchronous = "1" index = "31" label = "confirms a queue purge">
+      <doc>This method confirms the purge of a queue.</doc>
+
+      <chassis name = "client" implement = "MUST" />
+
+      <field name = "message-count" domain = "message-count">
+        <doc>
+          Reports the number of messages purged.
+        </doc>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "delete" synchronous = "1" index = "40" label = "delete a queue">
+      <doc>
+        This method deletes a queue. When a queue is deleted any pending messages are sent
+        to a dead-letter queue if this is defined in the server configuration, and all
+        consumers on the queue are cancelled.
+      </doc>
+
+      <rule name = "01">
+        <doc>
+          The server SHOULD use a dead-letter queue to hold messages that were pending on
+          a deleted queue, and MAY provide facilities for a system administrator to move
+          these messages back to an active queue.
+        </doc>
+      </rule>
+
+      <chassis name = "server" implement = "MUST" />
+
+      <response name = "delete-ok" />
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "queue" domain = "queue-name">
+        <doc>Specifies the name of the queue to delete.</doc>
+        <rule name = "queue-known" on-failure = "not-found">
+          <doc>
+            The client MUST either specify a queue name or have previously declared a
+            queue on the same channel
+          </doc>
+          <doc type = "scenario">
+            The client opens a channel and attempts to delete an unnamed queue.
+          </doc>
+        </rule>
+        <rule name = "must-exist" on-failure = "not-found">
+          <doc>
+            The client MUST NOT attempt to delete a queue that does not exist.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to delete a non-existent queue.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "if-unused" domain = "bit" label = "delete only if unused">
+        <doc>
+          If set, the server will only delete the queue if it has no consumers. If the
+          queue has consumers the server does does not delete it but raises a channel
+          exception instead.
+        </doc>
+        <rule name = "in-use" on-failure = "precondition-failed">
+          <doc>
+            The server MUST NOT delete a queue that has consumers on it, if the if-unused
+            field is true.
+          </doc>
+          <doc type = "scenario">
+            The client declares a queue, and consumes from it, then tries to delete it
+            setting if-unused to true.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "if-empty" domain = "bit" label = "delete only if empty">
+        <doc>
+          If set, the server will only delete the queue if it has no messages.
+        </doc>
+        <rule name = "not-empty" on-failure = "precondition-failed">
+          <doc>
+            The server MUST NOT delete a queue that has messages on it, if the
+            if-empty field is true.
+          </doc>
+          <doc type = "scenario">
+            The client declares a queue, binds it and publishes some messages into it,
+            then tries to delete it setting if-empty to true.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "no-wait" domain = "no-wait" />
+    </method>
+
+    <method name = "delete-ok" synchronous = "1" index = "41" label = "confirm deletion of a queue">
+      <doc>This method confirms the deletion of a queue.</doc>
+
+      <chassis name = "client" implement = "MUST" />
+
+      <field name = "message-count" domain = "message-count">
+        <doc>Reports the number of messages deleted.</doc>
+      </field>
+    </method>
+  </class>
+
+  <!-- ==  BASIC  ============================================================ -->
+
+  <class name = "basic" handler = "channel" index = "60" label = "work with basic content">
+    <doc>
+      The Basic class provides methods that support an industry-standard messaging model.
+    </doc>
+
+    <doc type = "grammar">
+      basic               = C:QOS S:QOS-OK
+                          / C:CONSUME S:CONSUME-OK
+                          / C:CANCEL S:CANCEL-OK
+                          / C:PUBLISH content
+                          / S:RETURN content
+                          / S:DELIVER content
+                          / C:GET ( S:GET-OK content / S:GET-EMPTY )
+                          / C:ACK
+                          / C:REJECT
+                          / C:RECOVER-ASYNC
+                          / C:RECOVER S:RECOVER-OK
+    </doc>
+
+    <chassis name = "server" implement = "MUST" />
+    <chassis name = "client" implement = "MAY" />
+
+    <rule name = "01">
+      <doc>
+        The server SHOULD respect the persistent property of basic messages and
+        SHOULD make a best-effort to hold persistent basic messages on a reliable
+        storage mechanism.
+      </doc>
+      <doc type = "scenario">
+        Send a persistent message to queue, stop server, restart server and then
+        verify whether message is still present.  Assumes that queues are durable.
+        Persistence without durable queues makes no sense.
+      </doc>
+    </rule>
+
+    <rule name = "02">
+      <doc>
+        The server MUST NOT discard a persistent basic message in case of a queue
+        overflow.
+      </doc>
+      <doc type = "scenario">
+        Declare a queue overflow situation with persistent messages and verify that
+        messages do not get lost (presumably the server will write them to disk).
+      </doc>
+    </rule>
+
+    <rule name = "03">
+      <doc>
+        The server MAY use the Channel.Flow method to slow or stop a basic message
+        publisher when necessary.
+      </doc>
+      <doc type = "scenario">
+        Declare a queue overflow situation with non-persistent messages and verify
+        whether the server responds with Channel.Flow or not. Repeat with persistent
+        messages.
+      </doc>
+    </rule>
+
+    <rule name = "04">
+      <doc>
+        The server MAY overflow non-persistent basic messages to persistent
+        storage.
+      </doc>
+      <!-- Test scenario: untestable -->
+    </rule>
+
+    <rule name = "05">
+      <doc>
+        The server MAY discard or dead-letter non-persistent basic messages on a
+        priority basis if the queue size exceeds some configured limit.
+      </doc>
+      <!-- Test scenario: untestable -->
+    </rule>
+
+    <rule name = "06">
+      <doc>
+        The server MUST implement at least 2 priority levels for basic messages,
+        where priorities 0-4 and 5-9 are treated as two distinct levels.
+      </doc>
+      <doc type = "scenario">
+        Send a number of priority 0 messages to a queue. Send one priority 9
+        message.  Consume messages from the queue and verify that the first message
+        received was priority 9.
+      </doc>
+    </rule>
+
+    <rule name = "07">
+      <doc>
+        The server MAY implement up to 10 priority levels.
+      </doc>
+      <doc type = "scenario">
+        Send a number of messages with mixed priorities to a queue, so that all
+        priority values from 0 to 9 are exercised. A good scenario would be ten
+        messages in low-to-high priority.  Consume from queue and verify how many
+        priority levels emerge.
+      </doc>
+    </rule>
+
+    <rule name = "08">
+      <doc>
+        The server MUST deliver messages of the same priority in order irrespective of
+        their individual persistence.
+      </doc>
+      <doc type = "scenario">
+        Send a set of messages with the same priority but different persistence
+        settings to a queue.  Consume and verify that messages arrive in same order
+        as originally published.
+      </doc>
+    </rule>
+
+    <rule name = "09">
+      <doc>
+        The server MUST support un-acknowledged delivery of Basic content, i.e.
+        consumers with the no-ack field set to TRUE.
+      </doc>
+    </rule>
+
+    <rule name = "10">
+      <doc>
+        The server MUST support explicitly acknowledged delivery of Basic content,
+        i.e. consumers with the no-ack field set to FALSE.
+      </doc>
+      <doc type = "scenario">
+        Declare a queue and a consumer using explicit acknowledgements.  Publish a
+        set of messages to the queue.  Consume the messages but acknowledge only
+        half of them.  Disconnect and reconnect, and consume from the queue.
+        Verify that the remaining messages are received.
+      </doc>
+    </rule>
+
+    <!--  These are the properties for a Basic content  -->
+
+    <!--  MIME typing -->
+    <field name = "content-type"    domain = "shortstr"   label = "MIME content type" />
+    <!--  MIME typing -->
+    <field name = "content-encoding" domain = "shortstr"  label = "MIME content encoding" />
+    <!--  For applications, and for header exchange routing -->
+    <field name = "headers"         domain = "table"      label = "message header field table" />
+    <!--  For queues that implement persistence -->
+    <field name = "delivery-mode"   domain = "octet"      label = "non-persistent (1) or persistent (2)" />
+    <!--  For queues that implement priorities -->
+    <field name = "priority"        domain = "octet"      label = "message priority, 0 to 9" />
+    <!--  For application use, no formal behaviour -->
+    <field name = "correlation-id"  domain = "shortstr"   label = "application correlation identifier" />
+    <!--  For application use, no formal behaviour but may hold the
+          name of a private response queue, when used in request messages -->
+    <field name = "reply-to"        domain = "shortstr"   label = "address to reply to" />
+    <!--  For implementation use, no formal behaviour -->
+    <field name = "expiration"      domain = "shortstr"   label = "message expiration specification" />
+    <!--  For application use, no formal behaviour -->
+    <field name = "message-id"      domain = "shortstr"   label = "application message identifier" />
+    <!--  For application use, no formal behaviour -->
+    <field name = "timestamp"       domain = "timestamp"  label = "message timestamp" />
+    <!--  For application use, no formal behaviour -->
+    <field name = "type"            domain = "shortstr"   label = "message type name" />
+    <!--  For application use, no formal behaviour -->
+    <field name = "user-id"         domain = "shortstr"   label = "creating user id" />
+    <!--  For application use, no formal behaviour -->
+    <field name = "app-id"          domain = "shortstr"   label = "creating application id" />
+    <!--  Deprecated, was old cluster-id property -->
+    <field name = "reserved"        domain = "shortstr"   label = "reserved, must be empty" />
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "qos" synchronous = "1" index = "10" label = "specify quality of service">
+      <doc>
+        This method requests a specific quality of service. The QoS can be specified for the
+        current channel or for all channels on the connection. The particular properties and
+        semantics of a qos method always depend on the content class semantics. Though the
+        qos method could in principle apply to both peers, it is currently meaningful only
+        for the server.
+      </doc>
+
+      <chassis name = "server" implement = "MUST" />
+      <response name = "qos-ok" />
+
+      <field name = "prefetch-size" domain = "long" label = "prefetch window in octets">
+        <doc>
+          The client can request that messages be sent in advance so that when the client
+          finishes processing a message, the following message is already held locally,
+          rather than needing to be sent down the channel. Prefetching gives a performance
+          improvement. This field specifies the prefetch window size in octets. The server
+          will send a message in advance if it is equal to or smaller in size than the
+          available prefetch size (and also falls into other prefetch limits). May be set
+          to zero, meaning "no specific limit", although other prefetch limits may still
+          apply. The prefetch-size is ignored if the no-ack option is set.
+        </doc>
+        <rule name = "01">
+          <doc>
+            The server MUST ignore this setting when the client is not processing any
+            messages - i.e. the prefetch size does not limit the transfer of single
+            messages to a client, only the sending in advance of more messages while
+            the client still has one or more unacknowledged messages.
+          </doc>
+          <doc type = "scenario">
+            Define a QoS prefetch-size limit and send a single message that exceeds
+            that limit.  Verify that the message arrives correctly.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "prefetch-count" domain = "short" label = "prefetch window in messages">
+        <doc>
+          Specifies a prefetch window in terms of whole messages. This field may be used
+          in combination with the prefetch-size field; a message will only be sent in
+          advance if both prefetch windows (and those at the channel and connection level)
+          allow it. The prefetch-count is ignored if the no-ack option is set.
+        </doc>
+        <rule name = "01">
+          <doc>
+            The server may send less data in advance than allowed by the client's
+            specified prefetch windows but it MUST NOT send more.
+          </doc>
+          <doc type = "scenario">
+            Define a QoS prefetch-size limit and a prefetch-count limit greater than
+            one.  Send multiple messages that exceed the prefetch size.  Verify that
+            no more than one message arrives at once.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "global" domain = "bit" label = "apply to entire connection">
+        <doc>
+          By default the QoS settings apply to the current channel only. If this field is
+          set, they are applied to the entire connection.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "qos-ok" synchronous = "1" index = "11" label = "confirm the requested qos">
+      <doc>
+        This method tells the client that the requested QoS levels could be handled by the
+        server. The requested QoS applies to all active consumers until a new QoS is
+        defined.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "consume" synchronous = "1" index = "20" label = "start a queue consumer">
+      <doc>
+        This method asks the server to start a "consumer", which is a transient request for
+        messages from a specific queue. Consumers last as long as the channel they were
+        declared on, or until the client cancels them.
+      </doc>
+
+      <rule name = "01">
+        <doc>
+          The server SHOULD support at least 16 consumers per queue, and ideally, impose
+          no limit except as defined by available resources.
+        </doc>
+        <doc type = "scenario">
+          Declare a queue and create consumers on that queue until the server closes the
+          connection. Verify that the number of consumers created was at least sixteen
+          and report the total number.
+        </doc>
+      </rule>
+
+      <chassis name = "server" implement = "MUST" />
+      <response name = "consume-ok" />
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "queue" domain = "queue-name">
+        <doc>Specifies the name of the queue to consume from.</doc>
+      </field>
+
+      <field name = "consumer-tag" domain = "consumer-tag">
+        <doc>
+          Specifies the identifier for the consumer. The consumer tag is local to a
+          channel, so two clients can use the same consumer tags. If this field is
+          empty the server will generate a unique tag.
+        </doc>
+        <rule name = "01" on-failure = "not-allowed">
+          <doc>
+            The client MUST NOT specify a tag that refers to an existing consumer.
+          </doc>
+          <doc type = "scenario">
+            Attempt to create two consumers with the same non-empty tag, on the
+            same channel.
+          </doc>
+        </rule>
+        <rule name = "02" on-failure = "not-allowed">
+          <doc>
+            The consumer tag is valid only within the channel from which the
+            consumer was created. I.e. a client MUST NOT create a consumer in one
+            channel and then use it in another.
+          </doc>
+          <doc type = "scenario">
+            Attempt to create a consumer in one channel, then use in another channel,
+            in which consumers have also been created (to test that the server uses
+            unique consumer tags).
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "no-local" domain = "no-local" />
+
+      <field name = "no-ack" domain = "no-ack" />
+
+      <field name = "exclusive" domain = "bit" label = "request exclusive access">
+        <doc>
+          Request exclusive consumer access, meaning only this consumer can access the
+          queue.
+        </doc>
+
+        <rule name = "01" on-failure = "access-refused">
+          <doc>
+            The client MAY NOT gain exclusive access to a queue that already has
+            active consumers.
+          </doc>
+          <doc type = "scenario">
+            Open two connections to a server, and in one connection declare a shared
+            (non-exclusive) queue and then consume from the queue.  In the second
+            connection attempt to consume from the same queue using the exclusive
+            option.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "no-wait" domain = "no-wait" />
+
+      <field name = "arguments" domain = "table" label = "arguments for declaration">
+        <doc>
+          A set of arguments for the consume. The syntax and semantics of these
+          arguments depends on the server implementation.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "consume-ok" synchronous = "1" index = "21" label = "confirm a new consumer">
+      <doc>
+        The server provides the client with a consumer tag, which is used by the client
+        for methods called on the consumer at a later stage.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+      <field name = "consumer-tag" domain = "consumer-tag">
+        <doc>
+          Holds the consumer tag specified by the client or provided by the server.
+        </doc>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "cancel" synchronous = "1" index = "30" label = "end a queue consumer">
+      <doc>
+        This method cancels a consumer. This does not affect already delivered
+        messages, but it does mean the server will not send any more messages for
+        that consumer. The client may receive an arbitrary number of messages in
+        between sending the cancel method and receiving the cancel-ok reply.
+      </doc>
+
+      <rule name = "01">
+        <doc>
+          If the queue does not exist the server MUST ignore the cancel method, so
+          long as the consumer tag is valid for that channel.
+        </doc>
+        <doc type = "scenario">
+          TODO.
+        </doc>
+      </rule>
+
+      <chassis name = "server" implement = "MUST" />
+      <response name = "cancel-ok" />
+
+      <field name = "consumer-tag" domain = "consumer-tag" />
+      <field name = "no-wait" domain = "no-wait" />
+    </method>
+
+    <method name = "cancel-ok" synchronous = "1" index = "31" label = "confirm a cancelled consumer">
+      <doc>
+        This method confirms that the cancellation was completed.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+      <field name = "consumer-tag" domain = "consumer-tag" />
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "publish" content = "1" index = "40" label = "publish a message">
+      <doc>
+        This method publishes a message to a specific exchange. The message will be routed
+        to queues as defined by the exchange configuration and distributed to any active
+        consumers when the transaction, if any, is committed.
+      </doc>
+
+      <chassis name = "server" implement = "MUST" />
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "exchange" domain = "exchange-name">
+        <doc>
+          Specifies the name of the exchange to publish to. The exchange name can be
+          empty, meaning the default exchange. If the exchange name is specified, and that
+          exchange does not exist, the server will raise a channel exception.
+        </doc>
+
+        <rule name = "must-exist" on-failure = "not-found">
+          <doc>
+            The client MUST NOT attempt to publish a content to an exchange that
+            does not exist.
+          </doc>
+          <doc type = "scenario">
+            The client attempts to publish a content to a non-existent exchange.
+          </doc>
+        </rule>
+        <rule name = "default-exchange">
+          <doc>
+            The server MUST accept a blank exchange name to mean the default exchange.
+          </doc>
+          <doc type = "scenario">
+            The client declares a queue and binds it to a blank exchange name.
+          </doc>
+        </rule>
+        <rule name = "02">
+          <doc>
+            If the exchange was declared as an internal exchange, the server MUST raise
+            a channel exception with a reply code 403 (access refused).
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+
+        <rule name = "03">
+          <doc>
+            The exchange MAY refuse basic content in which case it MUST raise a channel
+            exception with reply code 540 (not implemented).
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "routing-key" domain = "shortstr" label = "Message routing key">
+        <doc>
+          Specifies the routing key for the message. The routing key is used for routing
+          messages depending on the exchange configuration.
+        </doc>
+      </field>
+
+      <field name = "mandatory" domain = "bit" label = "indicate mandatory routing">
+        <doc>
+          This flag tells the server how to react if the message cannot be routed to a
+          queue. If this flag is set, the server will return an unroutable message with a
+          Return method. If this flag is zero, the server silently drops the message.
+        </doc>
+
+        <rule name = "01">
+          <doc>
+            The server SHOULD implement the mandatory flag.
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+      </field>
+
+      <field name = "immediate" domain = "bit" label = "request immediate delivery">
+        <doc>
+          This flag tells the server how to react if the message cannot be routed to a
+          queue consumer immediately. If this flag is set, the server will return an
+          undeliverable message with a Return method. If this flag is zero, the server
+          will queue the message, but with no guarantee that it will ever be consumed.
+        </doc>
+
+        <rule name = "01">
+          <doc>
+            The server SHOULD implement the immediate flag.
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+      </field>
+    </method>
+
+    <method name = "return" content = "1" index = "50" label = "return a failed message">
+      <doc>
+        This method returns an undeliverable message that was published with the "immediate"
+        flag set, or an unroutable message published with the "mandatory" flag set. The
+        reply code and text provide information about the reason that the message was
+        undeliverable.
+      </doc>
+
+      <chassis name = "client" implement = "MUST" />
+
+      <field name = "reply-code" domain = "reply-code" />
+      <field name = "reply-text" domain = "reply-text" />
+
+      <field name = "exchange" domain = "exchange-name">
+        <doc>
+          Specifies the name of the exchange that the message was originally published
+          to.  May be empty, meaning the default exchange.
+        </doc>
+      </field>
+
+      <field name = "routing-key" domain = "shortstr" label = "Message routing key">
+        <doc>
+          Specifies the routing key name specified when the message was published.
+        </doc>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "deliver" content = "1" index = "60"
+      label = "notify the client of a consumer message">
+      <doc>
+        This method delivers a message to the client, via a consumer. In the asynchronous
+        message delivery model, the client starts a consumer using the Consume method, then
+        the server responds with Deliver methods as and when messages arrive for that
+        consumer.
+      </doc>
+
+      <rule name = "01">
+        <doc>
+          The server SHOULD track the number of times a message has been delivered to
+          clients and when a message is redelivered a certain number of times - e.g. 5
+          times - without being acknowledged, the server SHOULD consider the message to be
+          unprocessable (possibly causing client applications to abort), and move the
+          message to a dead letter queue.
+        </doc>
+        <doc type = "scenario">
+          TODO.
+        </doc>
+      </rule>
+
+      <chassis name = "client" implement = "MUST" />
+
+      <field name = "consumer-tag" domain = "consumer-tag" />
+      <field name = "delivery-tag" domain = "delivery-tag" />
+      <field name = "redelivered" domain = "redelivered" />
+
+      <field name = "exchange" domain = "exchange-name">
+        <doc>
+          Specifies the name of the exchange that the message was originally published to.
+          May be empty, indicating the default exchange.
+        </doc>
+      </field>
+
+      <field name = "routing-key" domain = "shortstr" label = "Message routing key">
+        <doc>Specifies the routing key name specified when the message was published.</doc>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "get" synchronous = "1" index = "70" label = "direct access to a queue">
+      <doc>
+        This method provides a direct access to the messages in a queue using a synchronous
+        dialogue that is designed for specific types of application where synchronous
+        functionality is more important than performance.
+      </doc>
+
+      <response name = "get-ok" />
+      <response name = "get-empty" />
+      <chassis name = "server" implement = "MUST" />
+
+      <!-- Deprecated: "ticket", must be zero -->
+      <field name = "reserved-1" type = "short" reserved = "1" />
+
+      <field name = "queue" domain = "queue-name">
+        <doc>Specifies the name of the queue to get a message from.</doc>
+      </field>
+      <field name = "no-ack" domain = "no-ack" />
+    </method>
+
+    <method name = "get-ok" synchronous = "1" content = "1" index = "71"
+      label = "provide client with a message">
+      <doc>
+        This method delivers a message to the client following a get method. A message
+        delivered by 'get-ok' must be acknowledged unless the no-ack option was set in the
+        get method.
+      </doc>
+
+      <chassis name = "client" implement = "MAY" />
+
+      <field name = "delivery-tag" domain = "delivery-tag" />
+      <field name = "redelivered" domain = "redelivered" />
+      <field name = "exchange" domain = "exchange-name">
+        <doc>
+          Specifies the name of the exchange that the message was originally published to.
+          If empty, the message was published to the default exchange.
+        </doc>
+      </field>
+
+      <field name = "routing-key" domain = "shortstr" label = "Message routing key">
+        <doc>Specifies the routing key name specified when the message was published.</doc>
+      </field>
+
+      <field name = "message-count" domain = "message-count" />
+    </method>
+
+    <method name = "get-empty" synchronous = "1" index = "72"
+      label = "indicate no messages available">
+      <doc>
+        This method tells the client that the queue has no messages available for the
+        client.
+      </doc>
+      <chassis name = "client" implement = "MAY" />
+      <!-- Deprecated: "cluster-id", must be empty -->
+      <field name = "reserved-1" type = "shortstr" reserved = "1" />
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "ack" index = "80" label = "acknowledge one or more messages">
+      <doc>
+        This method acknowledges one or more messages delivered via the Deliver or Get-Ok
+        methods. The client can ask to confirm a single message or a set of messages up to
+        and including a specific message.
+      </doc>
+
+      <chassis name = "server" implement = "MUST" />
+
+      <field name = "delivery-tag" domain = "delivery-tag" />
+      <field name = "multiple" domain = "bit" label = "acknowledge multiple messages">
+        <doc>
+          If set to 1, the delivery tag is treated as "up to and including", so that the
+          client can acknowledge multiple messages with a single method. If set to zero,
+          the delivery tag refers to a single message. If the multiple field is 1, and the
+          delivery tag is zero, tells the server to acknowledge all outstanding messages.
+        </doc>
+        <rule name = "exists" on-failure = "precondition-failed">
+          <doc>
+            The server MUST validate that a non-zero delivery-tag refers to a delivered
+            message, and raise a channel exception if this is not the case.  On a transacted
+            channel, this check MUST be done immediately and not delayed until a Tx.Commit.
+            Specifically, a client MUST not acknowledge the same message more than once.
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "reject" index = "90" label = "reject an incoming message">
+      <doc>
+        This method allows a client to reject a message. It can be used to interrupt and
+        cancel large incoming messages, or return untreatable messages to their original
+        queue.
+      </doc>
+
+      <rule name = "01">
+        <doc>
+          The server SHOULD be capable of accepting and process the Reject method while
+          sending message content with a Deliver or Get-Ok method. I.e. the server should
+          read and process incoming methods while sending output frames. To cancel a
+          partially-send content, the server sends a content body frame of size 1 (i.e.
+          with no data except the frame-end octet).
+        </doc>
+      </rule>
+
+      <rule name = "02">
+        <doc>
+          The server SHOULD interpret this method as meaning that the client is unable to
+          process the message at this time.
+        </doc>
+        <doc type = "scenario">
+          TODO.
+        </doc>
+      </rule>
+
+      <rule name = "03">
+        <doc>
+          The client MUST NOT use this method as a means of selecting messages to process.
+        </doc>
+        <doc type = "scenario">
+          TODO.
+        </doc>
+      </rule>
+
+      <chassis name = "server" implement = "MUST" />
+
+      <field name = "delivery-tag" domain = "delivery-tag" />
+
+      <field name = "requeue" domain = "bit" label = "requeue the message">
+        <doc>
+          If requeue is true, the server will attempt to requeue the message.  If requeue
+          is false or the requeue  attempt fails the messages are discarded or dead-lettered.
+        </doc>
+
+        <rule name = "01">
+          <doc>
+            The server MUST NOT deliver the message to the same client within the
+            context of the current channel. The recommended strategy is to attempt to
+            deliver the message to an alternative consumer, and if that is not possible,
+            to move the message to a dead-letter queue. The server MAY use more
+            sophisticated tracking to hold the message on the queue and redeliver it to
+            the same client at a later stage.
+          </doc>
+          <doc type = "scenario">
+            TODO.
+          </doc>
+        </rule>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "recover-async" index = "100" label = "redeliver unacknowledged messages"
+        deprecated = "1">
+      <doc>
+        This method asks the server to redeliver all unacknowledged messages on a
+        specified channel. Zero or more messages may be redelivered.  This method
+        is deprecated in favour of the synchronous Recover/Recover-Ok.
+      </doc>
+      <rule name = "01">
+        <doc>
+          The server MUST set the redelivered flag on all messages that are resent.
+        </doc>
+        <doc type = "scenario">
+          TODO.
+        </doc>
+      </rule>
+      <chassis name = "server" implement = "MAY" />
+      <field name = "requeue" domain = "bit" label = "requeue the message">
+        <doc>
+          If this field is zero, the message will be redelivered to the original
+          recipient. If this bit is 1, the server will attempt to requeue the message,
+          potentially then delivering it to an alternative subscriber.
+        </doc>
+      </field>
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "recover" index = "110" label = "redeliver unacknowledged messages">
+      <doc>
+        This method asks the server to redeliver all unacknowledged messages on a
+        specified channel. Zero or more messages may be redelivered.  This method
+        replaces the asynchronous Recover.
+      </doc>
+      <rule name = "01">
+        <doc>
+          The server MUST set the redelivered flag on all messages that are resent.
+        </doc>
+        <doc type = "scenario">
+          TODO.
+        </doc>
+      </rule>
+      <chassis name = "server" implement = "MUST" />
+      <field name = "requeue" domain = "bit" label = "requeue the message">
+        <doc>
+          If this field is zero, the message will be redelivered to the original
+          recipient. If this bit is 1, the server will attempt to requeue the message,
+          potentially then delivering it to an alternative subscriber.
+        </doc>
+      </field>
+    </method>
+
+    <method name = "recover-ok" synchronous = "1" index = "111" label = "confirm recovery">
+      <doc>
+        This method acknowledges a Basic.Recover method.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+    </method>
+  </class>
+
+  <!-- ==  TX  =============================================================== -->
+
+  <class name = "tx" handler = "channel" index = "90" label = "work with transactions">
+    <doc>
+      The Tx class allows publish and ack operations to be batched into atomic
+      units of work.  The intention is that all publish and ack requests issued
+      within a transaction will complete successfully or none of them will.
+      Servers SHOULD implement atomic transactions at least where all publish
+      or ack requests affect a single queue.  Transactions that cover multiple
+      queues may be non-atomic, given that queues can be created and destroyed
+      asynchronously, and such events do not form part of any transaction.
+      Further, the behaviour of transactions with respect to the immediate and
+      mandatory flags on Basic.Publish methods is not defined.
+    </doc>
+
+    <rule name = "not multiple queues">
+      <doc>
+      Applications MUST NOT rely on the atomicity of transactions that
+      affect more than one queue.
+      </doc>
+    </rule>
+    <rule name = "not immediate">
+      <doc>
+      Applications MUST NOT rely on the behaviour of transactions that
+      include messages published with the immediate option.
+      </doc>
+    </rule>
+    <rule name = "not mandatory">
+      <doc>
+      Applications MUST NOT rely on the behaviour of transactions that
+      include messages published with the mandatory option.
+      </doc>
+    </rule>
+
+    <doc type = "grammar">
+      tx                  = C:SELECT S:SELECT-OK
+                          / C:COMMIT S:COMMIT-OK
+                          / C:ROLLBACK S:ROLLBACK-OK
+    </doc>
+
+    <chassis name = "server" implement = "SHOULD" />
+    <chassis name = "client" implement = "MAY" />
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "select" synchronous = "1" index = "10" label = "select standard transaction mode">
+      <doc>
+        This method sets the channel to use standard transactions. The client must use this
+        method at least once on a channel before using the Commit or Rollback methods.
+      </doc>
+      <chassis name = "server" implement = "MUST" />
+      <response name = "select-ok" />
+    </method>
+
+    <method name = "select-ok" synchronous = "1" index = "11" label = "confirm transaction mode">
+      <doc>
+        This method confirms to the client that the channel was successfully set to use
+        standard transactions.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "commit" synchronous = "1" index = "20" label = "commit the current transaction">
+      <doc>
+        This method commits all message publications and acknowledgments performed in
+        the current transaction.  A new transaction starts immediately after a commit.
+      </doc>
+      <chassis name = "server" implement = "MUST" />
+      <response name = "commit-ok" />
+
+      <rule name = "transacted" on-failure = "precondition-failed">
+        <doc>
+          The client MUST NOT use the Commit method on non-transacted channels.
+        </doc>
+        <doc type = "scenario">
+          The client opens a channel and then uses Tx.Commit.
+        </doc>
+      </rule>
+    </method>
+
+    <method name = "commit-ok" synchronous = "1" index = "21" label = "confirm a successful commit">
+      <doc>
+        This method confirms to the client that the commit succeeded. Note that if a commit
+        fails, the server raises a channel exception.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+    </method>
+
+    <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+    <method name = "rollback" synchronous = "1" index = "30"
+      label = "abandon the current transaction">
+      <doc>
+        This method abandons all message publications and acknowledgments performed in
+        the current transaction. A new transaction starts immediately after a rollback.
+        Note that unacked messages will not be automatically redelivered by rollback;
+        if that is required an explicit recover call should be issued.
+      </doc>
+      <chassis name = "server" implement = "MUST" />
+      <response name = "rollback-ok" />
+
+      <rule name = "transacted" on-failure = "precondition-failed">
+        <doc>
+          The client MUST NOT use the Rollback method on non-transacted channels.
+        </doc>
+        <doc type = "scenario">
+          The client opens a channel and then uses Tx.Rollback.
+        </doc>
+      </rule>
+    </method>
+
+    <method name = "rollback-ok" synchronous = "1" index = "31" label = "confirm successful rollback">
+      <doc>
+        This method confirms to the client that the rollback succeeded. Note that if an
+        rollback fails, the server raises a channel exception.
+      </doc>
+      <chassis name = "client" implement = "MUST" />
+    </method>
+  </class>
+
+</amqp>
diff --git a/setup.py b/setup.py
index fe3b9ae87d3a24da0152382bc308d61695e80e82..220c7eaba287e8f1e68975ed38c3ab6214cab6b9 100644
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,8 @@ setup(name='CoolAMQP',
       keywords=['amqp', 'pyamqp', 'rabbitmq', 'client', 'network', 'ha', 'high availability'],
       packages=[
           'coolamqp',
-          'coolamqp.backends'
+          'coolamqp.backends',
+          'coolamqp.framing',
       ],
       license='MIT License',
       long_description=u'The AMQP client that handles reconnection madness for you',
diff --git a/utils/__init__.py b/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f2b35b38d89264ee25685611d0a65a192e165f6
--- /dev/null
+++ b/utils/__init__.py
@@ -0,0 +1,2 @@
+# coding=UTF-8
+from __future__ import absolute_import, division, print_function
diff --git a/utils/compdefs.py b/utils/compdefs.py
new file mode 100644
index 0000000000000000000000000000000000000000..eb07d284aae5ea31c83023a3ba8ce9c4b9d0dfcb
--- /dev/null
+++ b/utils/compdefs.py
@@ -0,0 +1,228 @@
+from xml.etree import ElementTree
+import collections
+import struct
+import six
+
+from getp import get_constants, get_classes, get_domains, byname, name_class, name_method, name_field
+
+def frepr(p):
+    if isinstance(p, basestring):
+        p = six.text_type(p)
+    s = repr(p)
+
+    if isinstance(p, basestring) and not s.startswith('u'):
+        return 'u' + s
+    else:
+        return s
+
+def normname(p):
+    return p.strip().replace('-', '_').upper()
+
+def infertype(p):
+    try:
+        return int(p)
+    except ValueError:
+        return p
+
+def doxify(label, doc, prefix=4, blank=True): # output a full docstring section
+    label = [] if label is None else [label]
+    doc = [] if doc is None else doc.split(u'\n')
+    pre = u' '*prefix
+
+    doc = label + doc
+
+    if len(doc) == 0:
+        return u'\n'
+
+    doc[0] = doc[0].capitalize()
+
+    if len(doc) == 1:
+        return pre + doc[0] + u'\n'
+
+    if blank:
+        doc = [doc[0], u''] + doc[1:]
+
+    f = (u'\n'.join(pre + lin for lin in doc))[prefix:]
+    print(repr(f))
+    return f
+
+def ffmt(data, *args, **kwargs):
+    for arg in args:
+        op = str if kwargs.get('sane', True) else frepr
+        data = data.replace('%s', op(arg), 1)
+    return data
+
+def compile_definitions(xml_file='resources/amqp0-9-1.xml', out_file='coolamqp/framing/definitions.py'):
+    """parse resources/amqp-0-9-1.xml into """
+
+    xml = ElementTree.parse(xml_file)
+
+    with open(out_file, 'wb') as out:
+
+        out.write('''# coding=UTF-8
+from __future__ import print_function, absolute_import
+"""
+Constants used in AMQP protocol.
+
+Generated automatically by CoolAMQP from AMQP machine-readable specification.
+See utils/compdefs.py for the tool
+
+AMQP is copyright (c) 2016 OASIS
+CoolAMQP is copyright (c) 2016 DMS Serwis s.c.
+"""
+
+''')
+
+        def line(data, *args, **kwargs):
+            out.write(ffmt(data, *args, sane=True))
+
+        # Output core ones
+        line('# Core frame types\n')
+        for constant in get_constants(xml):
+            g = ffmt('%s = %s', constant.name.strip().replace('-', '_').upper(), constant.value)
+            line(g)
+            if constant.docs:
+                lines = constant.docs.split('\n')
+                line(' # %s\n', lines[0])
+                if len(lines) > 1:
+                    for ln in lines[1:]:
+                        line(u' '*len(g))
+                        line(u' # %s\n', ln)
+            else:
+                line('\n')
+
+        # get domains
+        domain_to_basic_type = {}
+        line('DOMAIN_TO_BASIC_TYPE = {\n')
+        for domain in get_domains(xml):
+            line(u'    %s: %s,\n', frepr(domain.name), frepr(None if domain.elementary else domain.type))
+            if not domain.elementary:
+                domain_to_basic_type[domain.name] = domain.type
+
+        line('}\n')
+
+        line('''
+
+class AMQPClass(object):
+    pass
+
+
+class AMQPMethod(object):
+    RESPONSE_TO = None
+    REPLY_WITH = []
+
+
+''')
+
+        # Output classes
+        for cls in get_classes(xml):
+            line('''class %s(AMQPClass):
+    """
+    %s
+    """
+    NAME = %s
+    INDEX = %s
+
+''', name_class(cls.name), doxify(None, cls.docs), frepr(cls.name), cls.index)
+
+            for method in cls.methods:
+
+
+                line('''\nclass %s%s(AMQPMethod):
+    """
+    %s
+    """
+    CLASS = %s
+    NAME = %s
+    CLASSNAME = %s
+    CLASS_INDEX = %s
+    METHOD_INDEX = %s
+    FULLNAME = %s
+    SYNCHRONOUS = %s
+    REPLY_WITH = [%s]
+''',
+                     name_class(cls.name), name_method(method.name),
+                     doxify(method.label, method.docs),
+                     name_class(cls.name),
+                     frepr(method.name),
+                     frepr(cls.name),
+                     frepr(cls.index),
+                     frepr(method.index),
+                     frepr(cls.name + '.' + method.name),
+                     repr(method.synchronous),
+                     str(', '.join([name_class(cls.name)+name_method(kidname) for kidname in method.response])),
+                     )
+
+                # Am I a response somewhere?
+                for paren in cls.methods:
+                    if method.name in paren.response:
+                        line('    RESPONSE_TO = %s%s\n', name_class(cls.name), name_method(paren.name))
+
+                # fields
+                line('    FIELDS = [')
+                for field in method.fields:
+                    tp = field.type
+                    while tp in domain_to_basic_type:
+                        tp = domain_to_basic_type[tp]
+
+                    line('\n        (%s, %s, %s), ', frepr(field.name), frepr(field.type), frepr(tp))
+                    if field.label:
+                        line(' # '+field.label)
+
+                line('\n    ]\n\n')
+
+                non_reserved_fields = [field for field in method.fields if not field.reserved]
+
+                # constructor
+                line('''    def __init__(%s):
+        """
+        Create frame %s
+
+''',
+                     u', '.join(['self'] + [name_field(field.name) for field in non_reserved_fields]),
+                     cls.name + '.' + method.name,
+                     )
+
+                for field in non_reserved_fields:
+                    tp = field.type
+                    while tp in domain_to_basic_type:
+                        tp = domain_to_basic_type[tp]
+
+                    if (field.label is not None) or (field.docs is not None):
+                        line('        :param %s: %s\n', name_field(field.name),
+                             doxify(field.label, field.docs, prefix=12, blank=False))
+                    line('        :type %s: %s (as %s)\n', name_field(field.name), field.type, tp)
+
+                line('        """\n')
+
+                for field in non_reserved_fields:
+                    line('        self.%s = %s\n', name_field(field.name), name_field(field.name))
+
+                # end
+                line('''\n    def to_frame(self):
+        """
+        Return self as bytes
+
+        :return: AMQP frame payload
+        """
+        raise NotImplementedError()
+
+''')
+
+
+
+            # Get me a dict - (classid, methodid) => class of method
+            dct = {}
+            for cls in get_classes(xml):
+                for method in cls.methods:
+                    dct[((cls.index, method.index))] = '%s%s' % (name_class(cls.name), name_method(method.name))
+
+        line('\nIDENT_TO_METHOD = {\n')
+        for k, v in dct.items():
+            line('    %s: %s,\n', repr(k), v)
+        line('}\n\n')
+
+
+
+if __name__ == '__main__':
+    compile_definitions()
diff --git a/utils/getp.py b/utils/getp.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad26d826c008092012e3f08cdafdb5f2cb87ff12
--- /dev/null
+++ b/utils/getp.py
@@ -0,0 +1,94 @@
+# coding=UTF-8
+from __future__ import absolute_import, division, print_function
+from collections import namedtuple
+import six
+
+# docs may be None
+
+Constant = namedtuple('Constant', ('name', 'value', 'kind', 'docs'))  # kind is AMQP constant class # value is int
+Field = namedtuple('Field', ('name', 'type', 'label', 'docs', 'reserved')) # reserved is bool
+Method = namedtuple('Method', ('name', 'synchronous', 'index', 'label', 'docs', 'fields', 'response'))
+        # synchronous is bool
+        # repponse is a list of method.name
+Class_ = namedtuple('Class_', ('name', 'index', 'docs', 'methods'))   # label is int
+Domain = namedtuple('Domain', ('name', 'type', 'elementary'))   # elementary is bool
+
+
+def get_docs(elem):
+    for kid in elem.getchildren():
+
+        if kid.tag == 'rule':
+            return get_docs(kid)
+
+        s = kid.text.strip().split('\n')
+        return u'\n'.join([u.strip() for u in s if len(u.strip()) > 0])
+
+    return None
+
+
+def for_domain(elem):
+    a = elem.attrib
+    return Domain(six.text_type(a['name']), a['type'], a['type'] == a['name'])
+
+
+def for_method_field(elem): # for <field> in <method>
+    a = elem.attrib
+    return Field(six.text_type(a['name']), a['domain'] if 'domain' in a else a['type'],
+                 a.get('label', None),
+                 get_docs(elem),
+                 a.get('reserved', '0') == '1')
+
+
+def for_method(elem):       # for <method>
+    a = elem.attrib
+    return Method(six.text_type(a['name']), bool(int(a.get('synchronous', '0'))), int(a['index']), a['label'], get_docs(elem),
+                  [for_method_field(fie) for fie in elem.getchildren() if fie.tag == 'field'],
+                  [e.attrib['name'] for e in elem.findall('response')]
+                  )
+
+def for_class(elem):        # for <class>
+    a = elem.attrib
+    methods = sorted([for_method(me) for me in elem.getchildren() if me.tag == 'method'], key=lambda m: (m.name.strip('-')[0], -len(m.response)))
+    return Class_(six.text_type(a['name']), int(a['index']), get_docs(elem) or a['label'], methods)
+
+def for_constant(elem):     # for <constant>
+    a = elem.attrib
+    return Constant(a['name'], int(a['value']), a.get('class', ''), get_docs(elem))
+
+
+def get_constants(xml):
+    return [for_constant(e) for e in xml.findall('constant')]
+
+def get_classes(xml):
+    return [for_class(e) for e in xml.findall('class')]
+
+def get_domains(xml):
+    return [for_domain(e) for e in xml.findall('domain')]
+
+
+def a_text(callable):
+    def roll(*args, **kwargs):
+        return six.text_type(callable(*args, **kwargs))
+    return roll
+
+def byname(list_of_things):
+    return dict((a.name, a) for a in list_of_things)
+
+@a_text
+def name_class(classname):
+    """Change AMQP class name to Python class name"""
+    return classname.capitalize()
+
+@a_text
+def name_method(methodname):
+    if '-' in methodname:
+        i = methodname.find('-')
+        return methodname[0:i].capitalize() + methodname[i+1].upper() + methodname[i+2:]
+    else:
+        return methodname.capitalize()
+
+@a_text
+def name_field(field):
+    if field in ('global', ):
+        field = field + '_'
+    return field.replace('-', '_')