The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
<?xml version="1.0"?>

<!--
  Copyright Notice
  ================
  (c) Copyright Cisco Systems, Credit Suisse, Deutsche Borse Systems, Envoy Technologies, Inc.,
  Goldman Sachs, IONA Technologies PLC, iMatix Corporation sprl.,JPMorgan Chase Bank Inc. N.A,
  Novell, Rabbit Technologies Ltd., Red Hat, Inc., TWIST Process Innovations ltd, and 29West Inc.
  2006, 2007. All rights reserved.

  License
  =======

  Cisco Systems, Credit Suisse, Deutsche Borse Systems, Envoy Technologies, Inc.,Goldman Sachs,
  IONA Technologies PLC, iMatix Corporation sprl.,JPMorgan Chase Bank Inc. N.A, Novell, Rabbit
  Technologies Ltd., Red Hat, Inc., TWIST Process Innovations ltd, 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 Protocol
  Specification, 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.envoytech.org/spec/amq/
  http://www.iona.com/opensource/amqp/
  http://www.redhat.com/solutions/specifications/amqp/
  http://www.twiststandards.org/tiki-index.php?page=AMQ
  http://www.imatix.com/amqp
-->

<!--
  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 hyphens (minus char '-') to seperate words in names.

  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.

-->

<!DOCTYPE amqp SYSTEM "amqp.dtd">

<amqp xmlns="http://www.amqp.org/schema/amqp.xsd"
    major="0" minor="10" port="5672">

  <!--
    ====================== == type definitions == ======================
  -->

  <!--
    0x00 - 0x0f: Fixed width, 1 octet
  -->

  <type name="bin8" code="0x00" fixed-width="1" label="octet of unspecified encoding">
    <doc>
      The bin8 type consists of exactly one octet of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET
      +----------+
      |   bin8   |
      +----------+
    </doc>

    <doc type="bnf">
               bin8 = OCTET
    </doc>
  </type>

  <type name="int8" code="0x01" fixed-width="1" label="8-bit signed integral value (-128 - 127)">
    <doc>
      The int8 type is a signed integral value encoded using an 8-bit two's complement
      representation.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET
      +----------+
      |   int8   |
      +----------+
    </doc>

    <doc type="bnf">
               int8 = OCTET
    </doc>
  </type>

  <type name="uint8" code="0x02" fixed-width="1" label="8-bit unsigned integral value (0 - 255)">
    <doc>
      The uint8 type is an 8-bit unsigned integral value.
    </doc>

    <doc type="picture" title="Wire Format">
        1 OCTET
      +---------+
      |  uint8  |
      +---------+
    </doc>

    <doc type="bnf">
              uint8 = OCTET
    </doc>
  </type>

  <type name="char" code="0x04" fixed-width="1" label="an iso-8859-15 character">
    <doc>
      The char type encodes a single character from the iso-8859-15 character set.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET
      +----------+
      |   char   |
      +----------+
    </doc>

    <doc type="bnf">
               char = OCTET
    </doc>
  </type>

  <type name="boolean" code="0x08" fixed-width="1"
        label="boolean value (zero represents false, nonzero represents true)">
    <doc>
      The boolean type is a single octet that encodes a true or false value. If the octet is zero,
      then the boolean is false. Any other value represents true.
    </doc>

    <doc type="picture" title="Wire Format">
        1 OCTET
      +---------+
      | boolean |
      +---------+
    </doc>

    <doc type="bnf">
            boolean = OCTET
    </doc>
  </type>

  <!--
    0x10 - 0x1f: Fixed width, 2 octets
  -->

  <type name="bin16" code="0x10" fixed-width="2" label="two octets of unspecified binary encoding">
    <doc>
      The bin16 type consists of two consecutive octets of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET
      +-----------+-----------+
      | octet-one | octet-two |
      +-----------+-----------+
    </doc>

    <doc type="bnf">
              bin16 = 2 OCTET
    </doc>
  </type>

  <type name="int16" code="0x11" fixed-width="2" label="16-bit signed integral value">
    <doc>
      The int16 type is a signed integral value encoded using a 16-bit two's complement
      representation in network byte order.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET    1 OCTET
      +-----------+----------+
      | high-byte | low-byte |
      +-----------+----------+
    </doc>

    <doc type="bnf">
              int16 = high-byte low-byte
          high-byte = OCTET
           low-byte = OCTET
    </doc>
  </type>

  <type name="uint16" code="0x12" fixed-width="2" label="16-bit unsigned integer">
    <doc>
      The uint16 type is a 16-bit unsigned integral value encoded in network byte order.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET    1 OCTET
      +-----------+----------+
      | high-byte | low-byte |
      +-----------+----------+
    </doc>

    <doc type="bnf">
             uint16 = high-byte low-byte
          high-byte = OCTET
           low-byte = OCTET
    </doc>
  </type>

  <!--
    0x20 - 0x2f: Fixed width, 4 octets
  -->

  <type name="bin32" code="0x20" fixed-width="4" label="four octets of unspecified binary encoding">
    <doc>
      The bin32 type consists of 4 consecutive octets of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET      1 OCTET      1 OCTET
      +-----------+-----------+-------------+------------+
      | octet-one | octet-two | octet-three | octet-four |
      +-----------+-----------+-------------+------------+
    </doc>

    <doc type="bnf">
              bin32 = 4 OCTET
    </doc>
  </type>

  <type name="int32" code="0x21" fixed-width="4" label="32-bit signed integral value">
    <doc>
      The int32 type is a signed integral value encoded using a 32-bit two's complement
      representation in network byte order.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET     1 OCTET    1 OCTET
      +-----------+------------+----------+----------+
      | byte-four | byte-three | byte-two | byte-one |
      +-----------+------------+----------+----------+
          MSB                                 LSB
    </doc>

    <doc type="bnf">
              int32 = byte-four byte-three byte-two byte-one
          byte-four = OCTET ; most significant byte (MSB)
         byte-three = OCTET
           byte-two = OCTET
           byte-one = OCTET ; least significant byte (LSB)
    </doc>
  </type>

  <type name="uint32" code="0x22" fixed-width="4" label="32-bit unsigned integral value">
    <doc>
      The uint32 type is a 32-bit unsigned integral value encoded in network byte order.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET     1 OCTET    1 OCTET
      +-----------+------------+----------+----------+
      | byte-four | byte-three | byte-two | byte-one |
      +-----------+------------+----------+----------+
          MSB                                 LSB
    </doc>

    <doc type="bnf">
             uint32 = byte-four byte-three byte-two byte-one
          byte-four = OCTET ; most significant byte (MSB)
         byte-three = OCTET
           byte-two = OCTET
           byte-one = OCTET ; least significant byte (LSB)
    </doc>
  </type>

  <type name="float" code="0x23" fixed-width="4"
        label="single precision IEEE 754 32-bit floating point">
    <doc>
      The float type encodes a single precision 32-bit floating point number. The format and
      operations are defined by the IEEE 754 standard for 32-bit floating point numbers.
    </doc>

    <doc type="picture" title="Wire Format">
              4 OCTETs
      +-----------------------+
      |         float         |
      +-----------------------+
        IEEE 754 32-bit float
    </doc>

    <doc type="bnf">
              float = 4 OCTET ; IEEE 754 32-bit floating point number
    </doc>
  </type>

  <type name="char-utf32" code="0x27" fixed-width="4"
        label="single unicode character in UTF-32 encoding">
    <doc>
      The char-utf32 type consists of a single unicode character in the UTF-32 encoding.
    </doc>

    <doc type="picture" title="Wire Format">
            4 OCTETs
      +------------------+
      |    char-utf32    |
      +------------------+
        UTF-32 character
    </doc>

    <doc type="bnf">
         char-utf32 = 4 OCTET ; single UTF-32 character
    </doc>
  </type>

  <type name="sequence-no" fixed-width="4" label="serial number defined in RFC-1982">
    <doc>
      The sequence-no type encodes, in network byte order, a serial number as defined in RFC-1982.
      The arithmetic, operators, and ranges for numbers of this type are defined by RFC-1982.
    </doc>

    <doc type="picture" title="Wire Format">
               4 OCTETs
      +------------------------+
      |      sequence-no       |
      +------------------------+
        RFC-1982 serial number
    </doc>

    <doc type="bnf">
        sequence-no = 4 OCTET ; RFC-1982 serial number
    </doc>
  </type>

  <!--
    0x30 - 0x3f: Fixed width types - 8 octets
  -->

  <type name="bin64" code="0x30" fixed-width="8"
        label="eight octets of unspecified binary encoding">
    <doc>
      The bin64 type consists of eight consecutive octets of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET            1 OCTET       1 OCTET
      +-----------+-----------+-----+-------------+-------------+
      | octet-one | octet-two | ... | octet-seven | octet-eight |
      +-----------+-----------+-----+-------------+-------------+
    </doc>

    <doc type="bnf">
              bin64 = 8 OCTET
    </doc>
  </type>

  <type name="int64" code="0x31" fixed-width="8" label="64-bit signed integral value">
    <doc>
      The int64 type is a signed integral value encoded using a 64-bit two's complement
      representation in network byte order.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET      1 OCTET           1 OCTET    1 OCTET
      +------------+------------+-----+----------+----------+
      | byte-eight | byte-seven | ... | byte-two | byte-one |
      +------------+------------+-----+----------+----------+
          MSB                                        LSB
    </doc>

    <doc type="bnf">
              int64 = byte-eight byte-seven byte-six byte-five
                      byte-four byte-three byte-two byte-one
         byte-eight = 1 OCTET ; most significant byte (MSB)
         byte-seven = 1 OCTET
           byte-six = 1 OCTET
          byte-five = 1 OCTET
          byte-four = 1 OCTET
         byte-three = 1 OCTET
           byte-two = 1 OCTET
           byte-one = 1 OCTET ; least significant byte (LSB)
    </doc>
  </type>

  <type name="uint64" code="0x32" fixed-width="8" label="64-bit unsigned integral value">
    <doc>
      The uint64 type is a 64-bit unsigned integral value encoded in network byte order.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET      1 OCTET           1 OCTET    1 OCTET
      +------------+------------+-----+----------+----------+
      | byte-eight | byte-seven | ... | byte-two | byte-one |
      +------------+------------+-----+----------+----------+
          MSB                                        LSB
    </doc>

    <doc type="bnf">
             uint64 = byte-eight byte-seven byte-six byte-five
                      byte-four byte-three byte-two byte-one
         byte-eight = 1 OCTET ; most significant byte (MSB)
         byte-seven = 1 OCTET
           byte-six = 1 OCTET
          byte-five = 1 OCTET
          byte-four = 1 OCTET
         byte-three = 1 OCTET
           byte-two = 1 OCTET
           byte-one = 1 OCTET ; least significant byte (LSB)
    </doc>
  </type>

  <type name="double" code="0x33" fixed-width="8" label="double precision IEEE 754 floating point">
    <doc>
      The double type encodes a double precision 64-bit floating point number. The format and
      operations are defined by the IEEE 754 standard for 64-bit double precision floating point
      numbers.
    </doc>

    <doc type="picture" title="Wire Format">
              8 OCTETs
      +-----------------------+
      |        double         |
      +-----------------------+
        IEEE 754 64-bit float
    </doc>

    <doc type="bnf">
             double = 8 OCTET ; double precision IEEE 754 floating point number
    </doc>
  </type>

  <type name="datetime" code="0x38" fixed-width="8" label="datetime in 64 bit POSIX time_t format">
    <doc>
      The datetime type encodes a date and time using the 64 bit POSIX time_t format.
    </doc>

    <doc type="picture" title="Wire Format">
             8 OCTETs
      +---------------------+
      |      datetime       |
      +---------------------+
        posix time_t format
    </doc>

    <doc type="bnf">
           datetime = 8 OCTET ; 64 bit posix time_t format
    </doc>
  </type>

  <!--
    0x40 - 0x4f: Fixed width types - 16 octets
  -->

  <type name="bin128" code="0x40" fixed-width="16"
        label="sixteen octets of unspecified binary encoding">
    <doc>
      The bin128 type consists of 16 consecutive octets of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET             1 OCTET         1 OCTET
      +-----------+-----------+-----+---------------+---------------+
      | octet-one | octet-two | ... | octet-fifteen | octet-sixteen |
      +-----------+-----------+-----+---------------+---------------+
    </doc>

    <doc type="bnf">
             bin128 = 16 OCTET
    </doc>
  </type>

  <type name="uuid" code="0x48" fixed-width="16" label="UUID (RFC-4122 section 4.1.2) - 16 octets">
    <doc>
      The uuid type encodes a universally unique id as defined by RFC-4122. The format and
      operations for this type can be found in section 4.1.2 of RFC-4122.
    </doc>

    <doc type="picture" title="Wire Format">
          16 OCTETs
      +---------------+
      |     uuid      |
      +---------------+
        RFC-4122 UUID
    </doc>

    <doc type="bnf">
               uuid = 16 OCTET ; RFC-4122 section 4.1.2
    </doc>
  </type>

  <!--
    0x50 - 0x5f: Fixed width types - 32 octets
  -->

  <type name="bin256" code="0x50" fixed-width="32"
        label="thirty two octets of unspecified binary encoding">
    <doc>
      The bin256 type consists of thirty two consecutive octets of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET              1 OCTET            1 OCTET
      +-----------+-----------+-----+------------------+------------------+
      | octet-one | octet-two | ... | octet-thirty-one | octet-thirty-two |
      +-----------+-----------+-----+------------------+------------------+
    </doc>

    <doc type="bnf">
             bin256 = 32 OCTET
    </doc>
  </type>

  <!--
    0x60 - 0x6f: Fixed width types - 64 octets
  -->

  <type name="bin512" code="0x60" fixed-width="64"
        label="sixty four octets of unspecified binary encoding">
    <doc>
      The bin512 type consists of sixty four consecutive octets of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET               1 OCTET            1 OCTET
      +-----------+-----------+-----+-------------------+------------------+
      | octet-one | octet-two | ... | octet-sixty-three | octet-sixty-four |
      +-----------+-----------+-----+-------------------+------------------+
    </doc>

    <doc type="bnf">
             bin512 = 64 OCTET
    </doc>
  </type>

  <!--
    0x70 - 0x7f: Fixed width types - 128 octets
  -->

  <type name="bin1024" code="0x70" fixed-width="128"
        label="one hundred and twenty eight octets of unspecified binary encoding">
    <doc>
      The bin1024 type consists of one hundred and twenty eight octets of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET                 1 OCTET                  1 OCTET
      +-----------+-----------+-----+------------------------+------------------------+
      | octet-one | octet-two | ... | octet-one-twenty-seven | octet-one-twenty-eight |
      +-----------+-----------+-----+------------------------+------------------------+
    </doc>

    <doc type="bnf">
            bin1024 = 128 OCTET
    </doc>
  </type>

  <!--
    0x80 - 0x8f: Variable length - one byte length field (up to 255 octets)
  -->

  <type name="vbin8" code="0x80" variable-width="1" label="up to 255 octets of opaque binary data">
    <doc>
      The vbin8 type encodes up to 255 octets of opaque binary data. The number of octets is first
      encoded as an 8-bit unsigned integral value. This is followed by the actual data.
    </doc>

    <doc type="picture" title="Wire Format">
        1 OCTET   size OCTETs
      +---------+-------------+
      |  size   |   octets    |
      +---------+-------------+
         uint8
    </doc>

    <doc type="bnf">
              vbin8 = size octets
               size = uint8
             octets = 0*255 OCTET ; size OCTETs
    </doc>
  </type>

  <type name="str8-latin" code="0x84" variable-width="1" label="up to 255 iso-8859-15 characters">
    <doc>
      The str8-latin type encodes up to 255 octets of iso-8859-15 characters. The number of octets
      is first encoded as an 8-bit unsigned integral value. This is followed by the actual
      characters.
    </doc>

    <doc type="picture" title="Wire Format">
        1 OCTET        size OCTETs
      +---------+------------------------+
      |  size   |       characters       |
      +---------+------------------------+
        uint16    iso-8859-15 characters
    </doc>

    <doc type="bnf">
         str8-latin = size characters
               size = uint8
         characters = 0*255 OCTET ; size OCTETs
    </doc>
  </type>

  <type name="str8" code="0x85" variable-width="1" label="up to 255 octets worth of UTF-8 unicode">
    <doc>
      The str8 type encodes up to 255 octets worth of UTF-8 unicode. The number of octets of unicode
      is first encoded as an 8-bit unsigned integral value. This is followed by the actual UTF-8
      unicode. Note that the encoded size refers to the number of octets of unicode, not necessarily
      the number of characters since the UTF-8 unicode may include multi-byte character sequences.
    </doc>

    <doc type="picture" title="Wire Format">
        1 OCTET   size OCTETs
      +---------+--------------+
      |  size   | utf8-unicode |
      +---------+--------------+
         uint8
    </doc>

    <doc type="bnf">
               str8 = size utf8-unicode
               size = uint8
       utf8-unicode = 0*255 OCTET ; size OCTETs
    </doc>
  </type>

  <type name="str8-utf16" code="0x86" variable-width="1"
        label="up to 255 octets worth of UTF-16 unicode">
    <doc>
      The str8-utf16 type encodes up to 255 octets worth of UTF-16 unicode. The number of octets of
      unicode is first encoded as an 8-bit unsigned integral value. This is followed by the actual
      UTF-16 unicode. Note that the encoded size refers to the number of octets of unicode, not the
      number of characters since the UTF-16 unicode will include at least two octets per unicode
      character.
    </doc>

    <doc type="picture" title="Wire Format">
        1 OCTET    size OCTETs
      +---------+---------------+
      |  size   | utf16-unicode |
      +---------+---------------+
         uint8
    </doc>

    <doc type="bnf">
         str8-utf16 = size utf16-unicode
               size = uint8
      utf16-unicode = 0*255 OCTET ; size OCTETs
    </doc>
  </type>

  <!--
    0x90 - 0x9f: Variable length types - two byte length field (up to 65535 octets)
  -->

  <type name="vbin16" code="0x90" variable-width="2"
        label="up to 65535 octets of opaque binary data">
    <doc>
      The vbin16 type encodes up to 65535 octets of opaque binary data. The number of octets is
      first encoded as a 16-bit unsigned integral value in network byte order. This is followed by
      the actual data.
    </doc>

    <doc type="picture" title="Wire Format">
        2 OCTETs   size OCTETs
      +----------+-------------+
      |   size   |   octets    |
      +----------+-------------+
         uint16
    </doc>

    <doc type="bnf">
             vbin16 = size octets
               size = uint16
             octets = 0*65535 OCTET ; size OCTETs
    </doc>
  </type>

  <type name="str16-latin" code="0x94" variable-width="2"
        label="up to 65535 iso-8859-15 characters">
    <doc>
      The str16-latin type encodes up to 65535 octets of is-8859-15 characters. The number of octets
      is first encoded as a 16-bit unsigned integral value in network byte order. This is followed
      by the actual characters.
    </doc>

    <doc type="picture" title="Wire Format">
        2 OCTETs        size OCTETs
      +----------+------------------------+
      |   size   |       characters       |
      +----------+------------------------+
         uint16    iso-8859-15 characters
    </doc>

    <doc type="bnf">
        str16-latin = size characters
               size = uint16
         characters = 0*65535 OCTET ; size OCTETs
    </doc>
  </type>

  <type name="str16" code="0x95" variable-width="2"
        label="up to 65535 octets worth of UTF-8 unicode">
    <doc>
      The str16 type encodes up to 65535 octets worth of UTF-8 unicode. The number of octets is
      first encoded as a 16-bit unsigned integral value in network byte order. This is followed by
      the actual UTF-8 unicode. Note that the encoded size refers to the number of octets of
      unicode, not necessarily the number of unicode characters since the UTF-8 unicode may include
      multi-byte character sequences.
    </doc>

    <doc type="picture" title="Wire Format">
        2 OCTETs   size OCTETs
      +----------+--------------+
      |   size   | utf8-unicode |
      +----------+--------------+
         uint16
    </doc>

    <doc type="bnf">
              str16 = size utf8-unicode
               size = uint16
       utf8-unicode = 0*65535 OCTET ; size OCTETs
    </doc>
  </type>

  <type name="str16-utf16" code="0x96" variable-width="2"
        label="up to 65535 octets worth of UTF-16 unicode">
    <doc>
      The str16-utf16 type encodes up to 65535 octets worth of UTF-16 unicode. The number of octets
      is first encoded as a 16-bit unsigned integral value in network byte order. This is followed
      by the actual UTF-16 unicode. Note that the encoded size refers to the number of octets of
      unicode, not the number of unicode characters since the UTF-16 unicode will include at least
      two octets per unicode character.
    </doc>

    <doc type="picture" title="Wire Format">
        2 OCTETs    size OCTETs
      +----------+---------------+
      |   size   | utf16-unicode |
      +----------+---------------+
         uint16
    </doc>

    <doc type="bnf">
        str16-utf16 = size utf16-unicode
               size = uint16
      utf16-unicode = 0*65535 OCTET ; size OCTETs
    </doc>
  </type>

  <type name="byte-ranges" variable-width="2" label="byte ranges within a 64-bit payload">
    <doc>
      The byte-ranges type encodes up to 65535 octets worth of non-overlapping, non-touching,
      ascending byte ranges within a 64-bit sequence of bytes. Each range is represented as an
      inclusive lower and upper bound that identifies all the byte offsets included within a given
      range.
    </doc>

    <doc>
      The number of octets of data is first encoded as a 16-bit unsigned integral value in network
      byte order. This is then followed by the encoded representation of the ranges included in the
      set. These MUST be encoded in ascending order, and any two ranges included in a given set MUST
      NOT include overlapping or touching byte offsets.
    </doc>

    <doc>
      Each range is encoded as a pair of 64-bit unsigned integral values in network byte order
      respectively representing the lower and upper bounds for that range. Note that because each
      range is exactly 16 octets, the size in octets of the encoded ranges will always be 16 times
      the number of ranges in the set.
    </doc>

    <doc type="picture" title="Wire Format">
                 +----= size OCTETs =----+
                 |                       |
        2 OCTETs |       16 OCTETs       |
      +----------+-----+-----------+-----+
      |   size   | .../|   range   |\... |
      +----------+---/ +-----------+ \---+
         uint16     / /             \ \
                   / /               \ \
                  / 8 OCTETs   8 OCTETs \
                 +-----------+-----------+
                 |   lower   |   upper   |
                 +-----------+-----------+
                     uint64     uint64
    </doc>

    <doc type="bnf">
        byte-ranges = size *range
               size = uint16
              range = lower upper
              lower = uint64
              upper = uint64
    </doc>
  </type>

  <type name="sequence-set" variable-width="2" label="ranged set representation">
    <doc>
      The sequence-set type is a set of pairs of RFC-1982 numbers representing a discontinuous range
      within an RFC-1982 sequence. Each pair represents a closed interval within the list.
    </doc>

    <doc>
      Sequence-sets can be represented as lists of pairs of positive 32-bit numbers, each pair
      representing a closed interval that does not overlap or touch with any other interval in the
      list. For example, a set containing words 0, 1, 2, 5, 6, and 15 can be represented:
    </doc>

    <doc type="picture">
      [(0, 2), (5, 6), (15, 15)]
    </doc>

    <doc>
      1) The list-of-pairs representation is sorted ascending (as defined by RFC 1982
      (http://www.ietf.org/rfc/rfc1982.txt) ) by the first elements of each pair.
    </doc>

    <doc>
      2) The list-of-pairs is flattened into a list-of-words.
    </doc>

    <doc>
      3) Each word in the list is packed into ascending locations in memory with network byte
      ordering.
    </doc>

    <doc>
      4) The size in bytes, represented as a 16-bit network-byte-order unsigned value, is prepended.
    </doc>

    <doc>
      For instance, the example from above would be encoded:
    </doc>

    <doc type="picture">
      [(0, 2), (5, 6), (15, 15)]                           -- already sorted.
      [0, 2, 5, 6, 15, 15]                                 -- flattened.
      000000000000000200000005000000060000000F0000000F     -- bytes in hex
      0018000000000000000200000005000000060000000F0000000F -- bytes in hex,
                                                              length (24) prepended
    </doc>

    <doc type="picture" title="Wire Format">
                 +----= size OCTETs =----+
                 |                       |
        2 OCTETs |       8 OCTETs        |
      +----------+-----+-----------+-----+
      |   size   | .../|   range   |\... |
      +----------+---/ +-----------+ \---+
         uint16     / /             \ \
                   / /               \ \
                  / /                 \ \
                 / /                   \ \
                / 4 OCTETs       4 OCTETs \
               +-------------+-------------+
               |    lower    |    upper    |
               +-------------+-------------+
                 sequence-no   sequence-no
    </doc>

    <doc type="bnf">
       sequence-set = size *range
               size = uint16         ; length of variable portion in bytes

              range = lower upper   ; inclusive
              lower = sequence-no
              upper = sequence-no
    </doc>
  </type>

  <!--
    0xa0 - 0xaf: Variable length types - four byte length field (up to 4294967295 octets)
  -->

  <type name="vbin32" code="0xa0" variable-width="4"
        label="up to 4294967295 octets of opaque binary data">
    <doc>
      The vbin32 type encodes up to 4294967295 octets of opaque binary data. The number of octets is
      first encoded as a 32-bit unsigned integral value in network byte order. This is followed by
      the actual data.
    </doc>

    <doc type="picture" title="Wire Format">
        4 OCTETs   size OCTETs
      +----------+-------------+
      |   size   |   octets    |
      +----------+-------------+
         uint32
    </doc>

    <doc type="bnf">
             vbin32 = size octets
               size = uint32
             octets = 0*4294967295 OCTET ; size OCTETs
    </doc>
  </type>

  <type name="map" code="0xa8" variable-width="4" label="a mapping of keys to typed values">
    <doc>
      A map is a set of distinct keys where each key has an associated (type,value) pair. The triple
      of the key, type, and value, form an entry within a map. Each entry within a given map MUST
      have a distinct key. A map is encoded as a size in octets, a count of the number of entries,
      followed by the encoded entries themselves.
    </doc>

    <doc>
      An encoded map may contain up to (4294967295 - 4) octets worth of encoded entries. The size is
      encoded as a 32-bit unsigned integral value in network byte order equal to the number of
      octets worth of encoded entries plus 4. (The extra 4 octets is added for the entry count.) The
      size is then followed by the number of entries encoded as a 32-bit unsigned integral value in
      network byte order. Finally the entries are encoded sequentially.
    </doc>

    <doc>
      An entry is encoded as the key, followed by the type, and then the value. The key is always a
      string encoded as a str8. The type is a single octet that may contain any valid AMQP type
      code. The value is encoded according to the rules defined by the type code for that entry.
    </doc>

    <doc type="picture" title="Wire Format">
                 +------------= size OCTETs =-----------+
                 |                                      |
        4 OCTETs | 4 OCTETs                             |
      +----------+----------+-----+---------------+-----+
      |   size   |  count   | .../|     entry     |\... |
      +----------+----------+---/ +---------------+ \---+
         uint32     uint32     / /                 \ \
                              / /                   \ \
                             / /                     \ \
                            / /                       \ \
                           / /                         \ \
                          / k OCTETs   1 OCTET   n OCTETs \
                         +-----------+---------+-----------+
                         |    key    |  type   |   value   |
                         +-----------+---------+-----------+
                             str8                 *type*
    </doc>

    <doc type="bnf">
                map = size count *entry

               size = uint32             ; size of count and entries in octets
              count = uint32             ; number of entries in the map

              entry = key type value
                key = str8
               type = OCTET              ; type code of the value
              value = *OCTET             ; the encoded value
    </doc>
  </type>

  <type name="list" code="0xa9" variable-width="4" label="a series of consecutive type-value pairs">
    <doc>
      A list is an ordered sequence of (type, value) pairs. The (type, value) pair forms an item
      within the list.  The list may contain items of many distinct types. A list is encoded as a
      size in octets, followed by a count of the number of items, followed by the items themselves
      encoded in their defined order.
    </doc>

    <doc>
      An encoded list may contain up to (4294967295 - 4) octets worth of encoded items. The size is
      encoded as a 32-bit unsigned integral value in network byte order equal to the number of
      octets worth of encoded items plus 4. (The extra 4 octets is added for the item count.) The
      size is then followed by the number of items encoded as a 32-bit unsigned integral value in
      network byte order. Finally the items are encoded sequentially in their defined order.
    </doc>

    <doc>
      An item is encoded as the type followed by the value. The type is a single octet that may
      contain any valid AMQP type code. The value is encoded according to the rules defined by the
      type code for that item.
    </doc>

    <doc type="picture" title="Wire Format">
                 +---------= size OCTETs =---------+
                 |                                 |
        4 OCTETs | 4 OCTETs                        |
      +----------+----------+-----+----------+-----+
      |   size   |  count   | .../|   item   |\... |
      +----------+----------+---/ +----------+ \---+
         uint32     uint32     / /            \ \
                              / /              \ \
                             / 1 OCTET   n OCTETs \
                            +----------+-----------+
                            |   type   |   value   |
                            +----------+-----------+
                                          *type*
    </doc>

    <doc type="bnf">
               list = size count *item

               size = uint32            ; size of count and items in octets
              count = uint32            ; number of items in the list

               item = type value
               type = OCTET             ; type code of the value
              value = *OCTET            ; the encoded value
    </doc>
  </type>

  <type name="array" code="0xaa" variable-width="4"
        label="a defined length collection of values of a single type">
    <doc>
      An array is an ordered sequence of values of the same type. The array is encoded in as a size
      in octets, followed by a type code, then a count of the number values in the array, and
      finally the values encoded in their defined order.
    </doc>

    <doc>
      An encoded array may contain up to (4294967295 - 5) octets worth of encoded values. The size
      is encoded as a 32-bit unsigned integral value in network byte order equal to the number of
      octets worth of encoded values plus 5. (The extra 5 octets consist of 4 octets for the count
      of the number of values, and one octet to hold the type code for the items in the array.) The
      size is then followed by a single octet that may contain any valid AMQP type code. The type
      code is then followed by the number of values encoded as a 32-bit unsigned integral value in
      network byte order. Finally the values are encoded sequentially in their defined order
      according to the rules defined by the type code for the array.
    </doc>

    <doc type="picture" title="Wire Format">
        4 OCTETs   1 OCTET   4 OCTETs      (size - 5) OCTETs
      +----------+---------+----------+-------------------------+
      |   size   |  type   |  count   |         values          |
      +----------+---------+----------+-------------------------+
         uint32               uint32    *count* encoded *types*
    </doc>

    <doc type="bnf">
              array = size type count values

               size = uint32            ; size of type, count, and values in octets
               type = OCTET             ; the type of the encoded values
              count = uint32            ; number of items in the array

             values = 0*4294967290 OCTET ; (size - 5) OCTETs
    </doc>
  </type>

  <type name="struct32" code="0xab" variable-width="4" label="a coded struct with a 32-bit size">
    <doc>
      The struct32 type describes any coded struct with a 32-bit (4 octet) size. The type is
      restricted to be only coded structs with a 32-bit size, consequently the first six octets of
      any encoded value for this type MUST always contain the size, class-code, and struct-code in
      that order.
    </doc>

    <doc>
      The size is encoded as a 32-bit unsigned integral value in network byte order that is equal to
      the size of the encoded field-data, packing-flags, class-code, and struct-code. The class-code
      is a single octet that may be set to any valid class code. The struct-code is a single octet
      that may be set to any valid struct code within the given class-code.
    </doc>

    <doc>
      The first six octets are then followed by the packing flags and encoded field data. The
      presence and quantity of packing-flags, as well as the specific fields are determined by the
      struct definition identified with the encoded class-code and struct-code.
    </doc>

    <doc type="picture" title="Wire Format">
        4 OCTETs    1 OCTET       1 OCTET     pack-width OCTETs    n OCTETs
      +----------+------------+-------------+-------------------+------------+
      |   size   | class-code | struct-code |   packing-flags   | field-data |
      +----------+------------+-------------+-------------------+------------+
         uint32

                          n = (size - 2 - pack-width)
    </doc>

    <doc type="bnf">
           struct32 = size class-code struct-code packing-flags field-data

               size = uint32

         class-code = OCTET     ; zero for top-level structs
        struct-code = OCTET     ; together with class-code identifies the struct
                                ; definition which determines the pack-width and
                                ; fields

      packing-flags = 0*4 OCTET ; pack-width OCTETs

         field-data = *OCTET    ; (size - 2 - pack-width) OCTETs
    </doc>
  </type>

  <!--
    0xb0 - 0xbf: Reserved
  -->

  <!--
    0xc0 - 0xcf:Fixed width types - 5 octets
  -->

  <type name="bin40" code="0xc0" fixed-width="5" label="five octets of unspecified binary encoding">
    <doc>
      The bin40 type consists of five consecutive octets of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET      1 OCTET      1 OCTET      1 OCTET
      +-----------+-----------+-------------+------------+------------+
      | octet-one | octet-two | octet-three | octet-four | octet-five |
      +-----------+-----------+-------------+------------+------------+
    </doc>

    <doc type="bnf">
              bin40 = 5 OCTET
    </doc>
  </type>

  <type name="dec32" code="0xc8" fixed-width="5"
        label="32-bit decimal value (e.g. for use in financial values)">
    <doc>
      The dec32 type is decimal value with a variable number of digits following the decimal point.
      It is encoded as an 8-bit unsigned integral value representing the number of decimal places.
      This is followed by the signed integral value encoded using a 32-bit two's complement
      representation in network byte order.
    </doc>

    <doc>
      The former value is referred to as the exponent of the divisor. The latter value is the
      mantissa. The decimal value is given by: mantissa / 10^exponent.
    </doc>

    <doc type="picture" title="Wire Format">
        1 OCTET    4 OCTETs
      +----------+----------+
      | exponent | mantissa |
      +----------+----------+
         uint8      int32
    </doc>

    <doc type="bnf">
              dec32 = exponent mantissa
           exponent = uint8
           mantissa = int32
    </doc>
  </type>

  <!--
    0xd0 - 0xdf: Fixed width types - 9 octets
  -->

  <type name="bin72" code="0xd0" fixed-width="9"
        label="nine octets of unspecified binary encoding">
    <doc>
      The bin72 type consists of nine consecutive octets of opaque binary data.
    </doc>

    <doc type="picture" title="Wire Format">
         1 OCTET     1 OCTET            1 OCTET      1 OCTET
      +-----------+-----------+-----+-------------+------------+
      | octet-one | octet-two | ... | octet-eight | octet-nine |
      +-----------+-----------+-----+-------------+------------+
    </doc>

    <doc type="bnf">
              bin64 = 9 OCTET
    </doc>
  </type>

  <type name="dec64" code="0xd8" fixed-width="9"
        label="64-bit decimal value (e.g. for use in financial values)">
    <doc>
      The dec64 type is decimal value with a variable number of digits following the decimal point.
      It is encoded as an 8-bit unsigned integral value representing the number of decimal places.
      This is followed by the signed integral value encoded using a 64-bit two's complement
      representation in network byte order.
    </doc>

    <doc>
      The former value is referred to as the exponent of the divisor. The latter value is the
      mantissa. The decimal value is given by: mantissa / 10^exponent.
    </doc>

    <doc type="picture" title="Wire Format">
        1 OCTET    8 OCTETs
      +----------+----------+
      | exponent | mantissa |
      +----------+----------+
         uint8      int64
    </doc>

    <doc type="bnf">
              dec64 = exponent mantissa
           exponent = uint8
           mantissa = int64
    </doc>
  </type>

  <!--
    0xe0 - 0xef: Reserved
  -->

  <!--
    0xf0 - 0xff: Zero-length types
  -->

  <type name="void" code="0xf0" fixed-width="0" label="the void type">
    <doc>
      The void type is used within tagged data structures such as maps and lists to indicate an
      empty value. The void type has no value and is encoded as an empty sequence of octets.
    </doc>
  </type>

  <type name="bit" code="0xf1" fixed-width="0" label="presence indicator">
    <doc>
      The bit type is used to indicate that a packing flag within a packed struct is being used to
      represent a boolean value based on the presence of an empty value. The bit type has no value
      and is encoded as an empty sequence of octets.
    </doc>
  </type>

  <!--
    ======================================================
    ==       CONSTANTS
    ======================================================
  -->

  <!-- Protocol constants -->

  <constant name="MIN-MAX-FRAME-SIZE" value="4096" label="The minimum size (in bytes) which can be
    agreed upon as the maximum frame size.">
    <doc>
      During the initial connection negotiation, the two peers must agree upon a maximum frame size.
      This constant defines the minimum value to which the maximum frame size can be set.  By
      defining this value, the peers can guarantee that they can send frames of up to this size
      until they have agreed a definitive maximum frame size for that connection.
    </doc>
  </constant>

  <!--
    ======================================================
    ==       DOMAIN TYPES
    ======================================================
  -->

  <!-- Segment types -->

  <domain name="segment-type" type="uint8" label="valid values for the frame type indicator.">
    <doc>
      Segments are defined in <xref ref="specification.transport.assemblies_segments_and_frames"/>.
      The segment domain defines the valid values that may be used for the segment indicator within
      the frame header.
    </doc>

    <enum>
      <choice name="control" value="0">
        <doc>
          The frame type indicator for Control segments (see <xref
          ref="specification.formal_notation.controls"/>).
        </doc>
      </choice>
      <choice name="command" value="1">
        <doc>
          The frame type indicator for Command segments (see <xref
            ref="specification.formal_notation.commands"/>).
        </doc>
      </choice>
      <choice name="header" value="2" >
        <doc>
          The frame type indicator for Header segments (see <xref
            ref="specification.formal_notation.segments.header"/>).
        </doc>
      </choice>
      <choice name="body" value="3" >
        <doc>
          The frame type indicator for Body segments (see <xref
            ref="specification.formal_notation.segments.body"/>).
        </doc>
      </choice>
    </enum>
  </domain>

  <!-- Tracks -->

  <domain name="track" type="uint8" label="Valid values for transport level tracks">
    <doc> Tracks are defined in <xref ref="specification.transport.channels_and_tracks"/>.  The
      track domain defines the valid values that may used for the track indicator within the frame
      header</doc>
    <enum>
      <choice name="control" value="0">
        <doc>
          The track used for all controls.  All controls defined in this specification MUST be sent
          on track 0.
        </doc>
      </choice>
      <choice name="command" value="1">
        <doc>
          The track used for all commands.  All commands defined in this specification MUST be sent
          on track 1.
        </doc>
      </choice>
    </enum>
  </domain>


  <domain name="str16-array" type="array" label="An array of values of type str16.">
    <doc>
      An array of values of type str16.
    </doc>
  </domain>



  <!-- == Class: connection ==================================================================== -->

  <class name="connection" code="0x1" label="work with connections">
    <doc>
      The connection class provides controls 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 | S:REDIRECT
      challenge         = S:SECURE C:SECURE-OK
      use-connection    = *channel
      close-connection  = C:CLOSE S:CLOSE-OK
                        / S:CLOSE C:CLOSE-OK
    </doc>

    <role name="server" implement="MUST" />
    <role name="client" implement="MUST" />

    <domain name="close-code" type="uint16" label="code used in the connection.close control to
      indicate reason for closure">
      <enum>
        <choice name="normal" value="200">
          <doc>
            The connection closed normally.
          </doc>
        </choice>

        <choice name="connection-forced" value="320">
          <doc>
            An operator intervened to close the connection for some reason. The client may retry at
            some later date.
          </doc>
        </choice>

        <choice name="invalid-path" value="402">
          <doc>
            The client tried to work with an unknown virtual host.
          </doc>
        </choice>

        <choice name="framing-error" value="501">
          <doc>
            A valid frame header cannot be formed from the incoming byte stream.
          </doc>
        </choice>
      </enum>
    </domain>

    <domain name="amqp-host-url" type="str16" label="URL for identifying an AMQP Server">
      <doc>
        The amqp-url domain defines a format for identifying an AMQP Server.  It is used to provide
        alternate hosts in the case where a client has to reconnect because of failure, or because
        the server requests the client to do so upon initial connection.
      </doc>
      <doc type="bnf"><![CDATA[
        amqp_url          = "amqp:" prot_addr_list
        prot_addr_list    = [prot_addr ","]* prot_addr
        prot_addr         = tcp_prot_addr | tls_prot_addr

        tcp_prot_addr     = tcp_id tcp_addr
        tcp_id            = "tcp:" | ""
        tcp_addr          = [host [":" port] ]
        host              = <as per http://www.ietf.org/rfc/rfc3986.txt>
        port              = number]]>
      </doc>
    </domain>

    <domain name="amqp-host-array" type="array" label="An array of values of type amqp-host-url">
      <doc>
        Used to provide a list of alternate hosts.
      </doc>
    </domain>

    <!-- - Control: connection.start - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="start" code="0x1" label="start connection negotiation">
      <doc>
        This control starts the connection negotiation process by telling the client the supported
        security mechanisms and locales from which the client can choose.
      </doc>

      <rule name="protocol-name">
        <doc>
          If the server cannot support the protocol specified in the protocol header, it MUST close
          the socket connection without sending any response control.
        </doc>
        <doc type="scenario">
          The client sends a protocol header containing an invalid protocol name. The server must
          respond by closing the connection.
        </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.
        </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.
        </doc>
      </rule>

      <implement role="client" handle="MUST" />

      <response name="start-ok" />

      <field name="server-properties" type="map" 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" type="str16-array" label="available security mechanisms"
             required="true">
        <doc>
          A list of the security mechanisms that the server supports.
        </doc>
      </field>

      <field name="locales" type="str16-array" label="available message locales" required="true">
        <doc>
          A list of the message locales that the server supports. 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>
      </field>
    </control>

    <!-- - Control: connection.start-ok  - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="start-ok" code="0x2" label="select security mechanism and locale">
      <doc>
        This control selects a SASL security mechanism.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="client-properties" type="map" 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" type="str8" label="selected security mechanism" required="true">
        <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 control, 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>
      </field>

      <field name="response" type="vbin32" label="security response data" required="true">
        <doc>
          A block of opaque data passed to the security mechanism. The contents of this data are
          defined by the SASL security mechanism.
        </doc>
      </field>

      <field name="locale" type="str8" label="selected message locale" required="true">
        <doc>
          A single message locale selected by the client, which must be one of those specified by
          the server.
        </doc>
      </field>
    </control>

    <!-- - Control: connection.secure  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="secure" code="0x3" 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 control challenges the
        client to provide more information.
      </doc>

      <implement role="client" handle="MUST" />

      <response name="secure-ok" />

      <field name="challenge" type="vbin32" label="security challenge data" required="true">
        <doc>
          Challenge information, a block of opaque binary data passed to the security mechanism.
        </doc>
      </field>
    </control>

    <!-- - Control: connection.secure-ok - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="secure-ok" code="0x4" label="security mechanism response">
      <doc>
        This control attempts to authenticate, passing a block of SASL data for the security
        mechanism at the server side.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="response" type="vbin32" label="security response data" required="true">
        <doc>
          A block of opaque data passed to the security mechanism. The contents of this data are
          defined by the SASL security mechanism.
        </doc>
      </field>
    </control>

    <!-- - Control: connection.tune  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="tune" code="0x5" label="propose connection tuning parameters">
      <doc>
        This control proposes a set of connection configuration values to the client. The client can
        accept and/or adjust these.
      </doc>

      <implement role="client" handle="MUST" />

      <response name="tune-ok" />

      <field name="channel-max" type="uint16" label="proposed maximum channels">
        <doc>
          The maximum total number of channels that the server allows per connection. If this is not
          set it means that the server does not impose a fixed limit, but the number of allowed
          channels may be limited by available server resources.
        </doc>
      </field>

      <field name="max-frame-size" type="uint16" label="proposed maximum frame size">
        <doc>
          The largest frame size that the server proposes for the connection. The client can
          negotiate a lower value. If this is not set 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 max-frame-size has been negotiated, both peers MUST accept frames of up to
            MIN-MAX-FRAME-SIZE octets large, and the minimum negotiated value for max-frame-size is
            also MIN-MAX-FRAME-SIZE.
          </doc>
          <doc type="scenario">
            Client connects to server and sends a large properties field, creating a frame of
            MIN-MAX-FRAME-SIZE octets. The server must accept this frame.
          </doc>
        </rule>
      </field>

      <field name="heartbeat-min" type="uint16" label="the minimum supported heartbeat delay">
        <doc>
          The minimum delay, in seconds, of the connection heartbeat supported by the server. If
          this is not set it means the server does not support sending heartbeats.
        </doc>
      </field>

      <field name="heartbeat-max" type="uint16" label="the maximum supported heartbeat delay">
        <doc>
          The maximum delay, in seconds, of the connection heartbeat supported by the server. If
          this is not set it means the server has no maximum.
        </doc>

        <rule name="permitted-range">
          <doc>
            The heartbeat-max value must be greater than or equal to the value supplied in the
            heartbeat-min field.
          </doc>
        </rule>

        <rule name="no-heartbeat-min">
          <doc>
            If no heartbeat-min is supplied, then the heartbeat-max field MUST remain empty.
          </doc>
        </rule>
      </field>
    </control>

    <!-- - Control: connection.tune-ok - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="tune-ok" code="0x6" label="negotiate connection tuning parameters">
      <doc>
        This control sends the client's connection tuning parameters to the server. Certain fields
        are negotiated, others provide capability information.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="channel-max" type="uint16" label="negotiated maximum channels" required="true">
        <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 implementers.
          </doc>

        </rule>

        <rule name="available-channels">
          <doc>
            If the client agrees to a channel-max of N channels, then the channels available for
            communication between client and server are precisely the channels numbered 0 to (N-1).
          </doc>
        </rule>
      </field>

      <field name="max-frame-size" type="uint16" label="negotiated maximum frame size">
        <doc>
          The largest frame size that the client and server will use for the connection. If it is
          not set 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 max-frame-size limit
          applies principally to content frames, where large contents can be broken into frames of
          arbitrary size.
        </doc>

        <rule name="minimum">
          <doc>
            Until the max-frame-size has been negotiated, both peers MUST accept frames of up to
            MIN-MAX-FRAME-SIZE octets large, and the minimum negotiated value for max-frame-size is
            also MIN-MAX-FRAME-SIZE.
          </doc>
        </rule>

        <rule name="upper-limit">
          <doc>
            If the client specifies a max-frame-size 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 implementers.
          </doc>
        </rule>

        <rule name="max-frame-size">
          <doc>
            A peer MUST NOT send frames larger than the agreed-upon size. A peer that receives an
            oversized frame MUST close the connection with the framing-error close-code.
          </doc>
        </rule>
      </field>

      <field name="heartbeat" type="uint16" label="negotiated heartbeat delay">
        <doc>
          The delay, in seconds, of the connection heartbeat chosen by the client. If it is not set
          it means the client does not want a heartbeat.
        </doc>

        <rule name="permitted-range">
          <doc>
            The chosen heartbeat MUST be in the range supplied by the heartbeat-min and
            heartbeat-max fields of connection.tune.
          </doc>
        </rule>

        <rule name="no-heartbeat-min">
          <doc>
            The heartbeat field MUST NOT be set if the heartbeat-min field of connection.tune was
            not set by the server.
          </doc>
        </rule>
      </field>
    </control>

    <!-- - Control: connection.open  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="open" code="0x7" label="open connection to virtual host">
      <doc>
        This control 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>

      <implement role="server" handle="MUST" />

      <response name="open-ok" />
      <response name="redirect" />

      <field name="virtual-host" type="str8" label="virtual host name"  required="true">
        <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>

      <field name="capabilities" type="str16-array" label="required capabilities">
        <doc>
          The client can specify zero or more capability names. The server can use this to determine
          how to process the client's connection request.
        </doc>
      </field>

      <field name="insist" type="bit" label="insist on connecting to server">
        <doc>
          In a configuration with multiple collaborating servers, the server may respond to a
          connection.open control with a Connection.Redirect. The insist option tells the server
          that the client is insisting on a connection to the specified server.
        </doc>
        <rule name="behavior">
          <doc>
            When the client uses the insist option, the server MUST NOT respond with a
            Connection.Redirect control. If it cannot accept the client's connection request it
            should respond by closing the connection with a suitable reply code.
          </doc>
        </rule>
      </field>
    </control>

    <!-- - Control: connection.open-ok - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="open-ok" code="0x8" label="signal that connection is ready">
      <doc>
        This control signals to the client that the connection is ready for use.
      </doc>

      <implement role="client" handle="MUST" />

      <field name="known-hosts" type="amqp-host-array" label="alternate hosts which may be used in
        the case of failure">
          <doc>
            Specifies an array of equivalent or alternative hosts that the server knows about, which
            will normally include the current server itself. Each entry in the array will be in the
            form of an IP address or DNS name, optionally followed by a colon and a port number.
            Clients can cache this information and use it when reconnecting to a server after a
            failure. This field may be empty.
          </doc>
      </field>
    </control>

    <!-- - Control: connection.redirect  - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="redirect" code="0x9" label="redirects client to other server">
      <doc>
        This control redirects the client to another server, based on the requested virtual host
        and/or capabilities.
      </doc>

      <rule name="usage">
        <doc>
          When getting the connection.redirect control, the client SHOULD reconnect to the host
          specified, and if that host is not present, to any of the hosts specified in the
          known-hosts list.
        </doc>
      </rule>

      <implement role="client" handle="MUST" />

      <field name="host" type="amqp-host-url" label="server to connect to" required="true">
        <doc>
          Specifies the server to connect to.
        </doc>
      </field>

      <field name="known-hosts" type="amqp-host-array" label="alternate hosts to try in case of
        failure">
        <doc>
          An array of equivalent or alternative hosts that the server knows about.
        </doc>
      </field>
    </control>

    <!-- - Control: connection.heartbeat - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="heartbeat" code="0xa" label="indicates connection is still alive">
      <doc>
        The heartbeat control may be used to generate artificial network traffic when a connection
        is idle. If a connection is idle for more than twice the negotiated heartbeat delay, the
        peers MAY be considered disconnected.
      </doc>
    </control>

    <!-- - Control: connection.close - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="close" code="0xb" label="request a connection close">
      <doc>
        This control indicates that the sender wants to close the connection. The reason for close
        is indicated with the reply-code and reply-text. The channel this control is sent on MAY be
        used to indicate which channel caused the connection to close.
      </doc>

      <implement role="client" handle="MUST" />
      <implement role="server" handle="MUST" />

      <response name="close-ok" />

      <field name="reply-code" type="close-code" label="the numeric reply code"
        required="true">
        <doc>
          Indicates the reason for connection closure.
        </doc>
      </field>
      <field name="reply-text" type="str8" label="the localized reply text">
        <doc>
          This text can be logged as an aid to resolving issues.
        </doc>
      </field>
    </control>

    <!-- - Control: connection.close-ok  - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <control name="close-ok" code="0xc" label="confirm a connection close">
      <doc>
        This control confirms a connection.close control 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 control
          SHOULD log the error.
        </doc>
      </rule>

      <implement role="client" handle="MUST" />
      <implement role="server" handle="MUST" />
    </control>

  </class>

  <!-- == Class: session ======================================================================= -->

  <class name="session" code="0x2" label="session controls">
    <doc>
      A session is a named interaction between two peers. Session names are chosen by the upper
      layers and may be used indefinitely. The model layer may associate long-lived or durable state
      with a given session name. The session layer provides transport of commands associated with
      this interaction.
    </doc>

    <doc>
      The controls defined within this class are specified in terms of the "sender" of commands and
      the "receiver" of commands. Since both client and server send and receive commands, the
      overall session dialog is symmetric, however the semantics of the session controls are defined
      in terms of a single sender/receiver pair, and it is assumed that the client and server will
      each contain both a sender and receiver implementation.
    </doc>

    <rule name="attachment">
      <doc>
        The transport MUST be attached in order to use any control other than "attach", "attached",
        "detach", or "detached". A peer receiving any other control on a detached transport MUST
        discard it and send a session.detached with the "not-attached" reason code.
      </doc>
    </rule>

    <role name="server" implement="MUST" />
    <role name="client" implement="MUST" />

    <role name="sender" implement="MUST">
      <doc>
        The sender of commands.
      </doc>
    </role>
    <role name="receiver" implement="MUST">
      <doc>
        The receiver of commands.
      </doc>
    </role>

    <domain name="name" type="vbin16" label="opaque session name">
      <doc>
        The session name uniquely identifies an interaction between two peers. It is scoped to a
        given authentication principal.
      </doc>
    </domain>

    <domain name="detach-code" type="uint8" label="reason for detach">
      <enum>
        <choice name="normal" value="0">
          <doc>
            The session was detached by request.
          </doc>
        </choice>
        <choice name="session-busy" value="1">
          <doc>
            The session is currently attached to another transport.
          </doc>
        </choice>
        <choice name="transport-busy" value="2">
          <doc>
            The transport is currently attached to another session.
          </doc>
        </choice>
        <choice name="not-attached" value="3">
          <doc>
            The transport is not currently attached to any session.
          </doc>
        </choice>
        <choice name="unknown-ids" value="4">
          <doc>
            Command data was received prior to any use of the command-point control.
          </doc>
        </choice>
      </enum>
    </domain>

    <domain name="commands" type="sequence-set" label="identifies a set of commands">
    </domain>

    <struct name="header" size="1" pack="1">
      <doc>
        The session header appears on commands after the class and command id, but prior to command
        arguments.
      </doc>

      <field name="sync" type="bit" label="request notification of completion">
        <doc>
          Request notification of completion for this command.
        </doc>
      </field>
    </struct>

    <struct name="command-fragment" size="0" pack="0" label="byte-ranges within a set of commands">

      <field name="command-id" type="sequence-no" required="true">

      </field>
      <field name="byte-ranges" type="byte-ranges" required="true">

      </field>
    </struct>

    <domain name="command-fragments" type="array" label="an array of values of type
      command-fragment"/>

    <control name="attach" code="0x1" label="attach to the named session">
      <doc>
        Requests that the current transport be attached to the named session. Success or failure
        will be indicated with an attached or detached response. This control is idempotent.
      </doc>

      <rule name="one-transport-per-session">
        <doc>
          A session MUST NOT be attached to more than one transport at a time.
        </doc>
      </rule>

      <rule name="one-session-per-transport">
        <doc>
          A transport MUST NOT be attached to more than one session at a time.
        </doc>
      </rule>

      <rule name="idempotence">
        <doc>
          Attaching a session to its current transport MUST succeed and result in an attached
          response.
        </doc>
      </rule>

      <rule name="scoping">
        <doc>
          Attachment to the same session name from distinct authentication principals MUST succeed.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MAY" />

      <response name="attached"/>
      <response name="detached"/>

      <field name="name" type="name" label="the session name" required="true">
        <doc>
          Identifies the session to be attached to the current transport.
        </doc>
      </field>

      <field name="force" type="bit" label="force attachment to a busy session">
        <doc>
          If set then a busy session will be forcibly detached from its other transport and
          reattached to the current transport.
        </doc>
      </field>
    </control>

    <control name="attached" code="0x2" label="confirm attachment to the named session">
      <doc>
        Confirms successful attachment of the transport to the named session.
      </doc>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <field name="name" type="name" label="the session name" required="true">
        <doc>
          Identifies the session now attached to the current transport.
        </doc>
      </field>
    </control>

    <control name="detach" code="0x3" label="detach from the named session">
      <doc>
        Detaches the current transport from the named session.
      </doc>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <response name="detached"/>

      <field name="name" type="name" label="the session name" required="true">
        <doc>
          Identifies the session to detach.
        </doc>
      </field>
    </control>

    <control name="detached" code="0x4" label="confirm detachment from the named session">
      <doc>
        Confirms detachment of the current transport from the named session.
      </doc>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <field name="name" type="name" label="the session name" required="true">
        <doc>
          Identifies the detached session.
        </doc>
      </field>
      <field name="code" type="detach-code" label="the reason for detach" required="true">
        <doc>
          Identifies the reason for detaching from the named session.
        </doc>
      </field>
    </control>

    <!--
        Execution state is the set of confirmed, and completed incoming commands, as well as the set
        of outgoing in-doubt commands held for replay.
    -->

    <control name="request-timeout" code="0x5" label="requests the execution timeout be changed">
      <doc>
        This control may be sent by either the sender or receiver of commands. It requests that the
        execution timeout be changed. This is the minimum amount of time that a peer must preserve
        execution state for a detached session.
      </doc>

      <rule name="maximum-granted-timeout">
        <doc>
          The handler of this request MUST set his timeout to the maximum allowed value less than or
          equal to the requested timeout, and MUST convey the chosen timeout in the response.
        </doc>
      </rule>

      <implement role="sender" handle="MUST" />
      <implement role="receiver" handle="MUST" />

      <response name="timeout"/>

      <field name="timeout" type="uint32" label="the requested timeout">
        <doc>
          The requested timeout for execution state in seconds. If not set, this control requests
          that execution state is preserved indefinitely.
        </doc>
      </field>
    </control>

    <control name="timeout" code="0x6" label="the granted timeout">
      <doc>
        This control may be sent by the either the sender or receiver of commands. It is a
        one-to-one reply to the request-timeout control that indicates the granted timeout for
        execution state.
      </doc>

      <implement role="sender" handle="MUST" />
      <implement role="receiver" handle="MUST" />

      <field name="timeout" type="uint32" label="the execution timeout">
        <doc>
          The timeout for execution state. If not set, then execution state is preserved
          indefinitely.
        </doc>
      </field>
    </control>

    <control name="command-point" code="0x7"
             label="the command id and byte offset of subsequent data">
      <doc>
        This control is sent by the sender of commands and handled by the receiver of commands. This
        establishes the sequence numbers associated with all subsequent command data sent from the
        sender to the receiver. The subsequent command data will be numbered starting with the
        values supplied in this control and proceeding sequentially. This must be used at least once
        prior to sending any command data on newly attached transports.
      </doc>

      <rule name="newly-attached-transports">
        <doc>
          If command data is sent on a newly attached transport the session MUST be detached with an
          "unknown-id" reason-code.
        </doc>
      </rule>

      <rule name="zero-offset">
        <doc>
          If the offset is zero, the next data frame MUST have the first-frame and first-segment
          flags set. Violation of this is a framing error.
        </doc>
      </rule>

      <rule name="nonzero-offset">
        <doc>
          If the offset is nonzero, the next data frame MUST NOT have both the first-frame and
          first-segment flag set. Violation of this is a framing error.
        </doc>
      </rule>

      <implement role="receiver" handle="MUST" />

      <field name="command-id" type="sequence-no" label="the command-id of the next command"
        required="true"/>
      <field name="command-offset" type="uint64" label="the byte offset within the command"
        required="true"/>
    </control>

    <control name="expected" code="0x8" label="informs the peer of expected commands">
      <doc>
        This control is sent by the receiver of commands and handled by the sender of commands. It
        informs the sender of what commands and command fragments are expected at the receiver.
        This control is only sent in response to a flush control with the expected flag set.  The
        expected control is never sent spontaneously.
      </doc>

      <rule name="include-next-command">
        <doc>
          The set of expected commands MUST include the next command after the highest seen command.
        </doc>
      </rule>

      <rule name="commands-empty-means-new-session">
        <doc>
          The set of expected commands MUST have zero elements if and only if the sender holds no
          execution state for the session (i.e. it is a new session).
        </doc>
      </rule>

      <rule name="no-overlaps">
        <doc>
          If a command-id appears in the commands field, it MUST NOT appear in the fragments field.
        </doc>
      </rule>

      <rule name="minimal-fragments">
        <doc>
          When choice is permitted, a command MUST appear in the commands field rather than the
          fragments field.
        </doc>
      </rule>

      <implement role="sender" handle="MUST" />

      <field name="commands" type="commands" label="expected commands" required="true"/>
      <field name="fragments" type="command-fragments" label="expected fragments" />
    </control>

    <control name="confirmed" code="0x9" label="notifies of confirmed commands">
      <doc>
        This control is sent by the receiver of commands and handled by the sender of commands. This
        sends the set of commands that will definitely be completed by this peer to the sender. This
        excludes commands known by the receiver to be considered confirmed or complete at the
        sender.
      </doc>
      <doc>
        This control must be sent if the partner requests the set of confirmed commands using the
        session.flush control with the confirmed flag set.
      </doc>
      <doc>
        This control may be sent spontaneously.  One reason for separating confirmation from
        completion is for large persistent messages, where the receipt (and storage to a durable
        store) of part of the message will result in less data needing to be replayed in the case of
        transport failure during transmission.
      </doc>
      <doc>
        A simple implementation of an AMQP client or server may be implemented to take no action on
        receipt of session.confirmed controls, and take action only when receiving
        session.completed controls.
      </doc>
      <doc>
        A simple implementation of an AMQP client or server may be implemented such that it never
        spontaneously sends session.confirmed and that when requested for the set of confirmed
        commands (via the session.flush control) it responds with the same set of commands as it
        would to when the set of completed commands was requested (trivially all completed commands
        are confirmed).
      </doc>

      <rule name="durability">
        <doc>
          If a command has durable implications, it MUST NOT be confirmed until the fact of the
          command has been recorded on durable media.
        </doc>
      </rule>

      <rule name="no-overlaps">
        <doc>
          If a command-id appears in the commands field, it MUST NOT appear in the fragments field.
        </doc>
      </rule>

      <rule name="minimal-fragments">
        <doc>
          When choice is permitted, a command MUST appear in the commands field rather than the
          fragments field.
        </doc>
      </rule>

      <implement role="sender" handle="MUST" />

      <field name="commands" type="commands" label="entirely confirmed commands">
        <rule name="exclude-known-complete">
          <doc>
            Command-ids included in prior known-complete replies MUST be excluded from the set of
            all confirmed commands.
          </doc>
        </rule>
      </field>
      <field name="fragments" type="command-fragments" label="partially confirmed commands"/>
    </control>

    <control name="completed" code="0xa" label="notifies of command completion">
      <doc>
        This control is sent by the receiver of commands, and handled by the sender of commands. It
        informs the sender of all commands completed by the receiver. This excludes commands known
        by the receiver to be considered complete at the sender.
      </doc>

      <rule name="known-completed-reply">
        <doc>
          The sender MUST eventually reply with a known-completed set that covers the completed ids.
        </doc>
      </rule>

      <rule name="delayed-reply">
        <doc>
          The known-complete reply MAY be delayed at the senders discretion if the timely-reply
          field is not set.
        </doc>
      </rule>

      <rule name="merged-reply">
        <doc>
          Multiple replies may be merged by sending a single known-completed that includes the union
          of the merged command-id sets.
        </doc>
      </rule>

      <implement role="sender" handle="MUST" />

      <field name="commands" type="commands" label="completed commands">
        <doc>
          The ids of all completed commands. This excludes commands known by the receiver to be
          considered complete at the sender.
        </doc>

        <rule name="completed-implies-confirmed">
          <doc>
            The sender MUST consider any completed commands to also be confirmed.
          </doc>
        </rule>

        <rule name="exclude-known-complete">
          <doc>
            Command-ids included in prior known-complete replies MUST be excluded from the set of
            all completed commands.
          </doc>
        </rule>
      </field>
      <field name="timely-reply" type="bit">
        <doc>
          If set, the sender is no longer free to delay the known-completed reply.
        </doc>
      </field>
    </control>

    <control name="known-completed" code="0xb" label="Inform peer of which commands are known to be
      completed">
      <doc>
        This control is sent by the sender of commands, and handled by the receiver of commands. It
        is sent in reply to one or more completed controls from the receiver. It informs the
        receiver that commands are known to be completed by the sender.
      </doc>

      <rule name="stateless">
        <doc>
          The sender need not keep state to generate this reply. It is sufficient to reply to any
          completed control with an exact echo of the completed ids.
        </doc>
      </rule>

      <implement role="receiver" handle="MUST" />

      <field name="commands" type="commands" label="commands known to be complete">
        <doc>
          The set of completed commands for one or more session.completed controls.
        </doc>

        <rule name="known-completed-implies-known-confirmed">
          <doc>
            The receiver MUST treat any of the specified commands to be considered by the sender as
            confirmed as well as completed.
          </doc>
        </rule>
      </field>
    </control>

    <control name="flush" code="0xc" label="requests a session.completed">
      <doc>
        This control is sent by the sender of commands and handled by the receiver of commands. It
        requests that the receiver produce the indicated command sets. The receiver should issue the
        indicated sets at the earliest possible opportunity.
      </doc>

      <implement role="receiver" handle="MUST" />

      <field name="expected" type="bit" label="request notification of expected commands"/>
      <field name="confirmed" type="bit" label="request notification of confirmed commands"/>
      <field name="completed" type="bit" label="request notification of completed commands"/>
    </control>

    <control name="gap" code="0xd" label="indicates missing segments in the stream">
      <doc>
        This control is sent by the sender of commands and handled by the receiver of commands. It
        sends command ranges for which there will be no further data forthcoming. The receiver
        should proceed with the next available commands that arrive after the gap.
      </doc>

      <rule name="gap-confirmation-and-completion">
        <doc>
          The command-ids covered by a session.gap MUST be added to the completed and confirmed sets
          by the receiver.
        </doc>
      </rule>

      <rule name="aborted-commands">
        <doc>
          If a session.gap covers a partially received command, the receiving peer MUST treat the
          command as aborted.
        </doc>
      </rule>

      <rule name="completed-or-confirmed-commands">
        <doc>
          If a session.gap covers a completed or confirmed command, the receiving peer MUST continue
          to treat the command as completed or confirmed.
        </doc>
      </rule>

      <implement role="receiver" handle="MUST" />

      <field name="commands" type="commands">
        <doc>
          The set of command-ids that are contained in this gap.
        </doc>
      </field>
    </control>

  </class>

  <!-- == Class: execution ===================================================================== -->

  <class name="execution" code="0x3" label="execution commands">
    <doc>
      The execution class provides commands that carry execution information about other model level
      commands.
    </doc>

    <role name="server" implement="MUST"/>
    <role name="client" implement="MUST"/>

    <domain name="error-code" type="uint16">
      <enum>
        <choice name="unauthorized-access" value="403">
          <doc>
            The client attempted to work with a server entity to which it has no access due to
            security settings.
          </doc>
        </choice>

        <choice name="not-found" value="404">
          <doc>
            The client attempted to work with a server entity that does not exist.
          </doc>
        </choice>

        <choice name="resource-locked" value="405">
          <doc>
            The client attempted to work with a server entity to which it has no access because
            another client is working with it.
          </doc>
        </choice>

        <choice name="precondition-failed" value="406">
          <doc>
            The client requested a command that was not allowed because some precondition failed.
          </doc>
        </choice>

        <choice name="resource-deleted" value="408">
          <doc>
            A server entity the client is working with has been deleted.
          </doc>
        </choice>

        <choice name="illegal-state" value="409">
          <doc>
            The peer sent a command that is not permitted in the current state of the session.
          </doc>
        </choice>

        <choice name="command-invalid" value="503">
          <doc>
            The command segments could not be decoded.
          </doc>
        </choice>

        <choice name="resource-limit-exceeded" value="506">
          <doc>
            The client exceeded its resource allocation.
          </doc>
        </choice>

        <choice name="not-allowed" value="530">
          <doc>
            The peer tried to use a command a manner that is inconsistent with the rules described
            in the specification.
          </doc>
        </choice>

        <choice name="illegal-argument" value="531">
          <doc>
            The command argument is malformed, i.e. it does not fall within the specified domain.
            The illegal-argument exception can be raised on execution of any command which has
            domain valued fields.
          </doc>
        </choice>

        <choice name="not-implemented" value="540">
          <doc>
            The peer tried to use functionality that is not implemented in its partner.
          </doc>
        </choice>

        <choice name="internal-error" value="541">
          <doc>
            The peer could not complete the command because of an internal error. The peer may
            require intervention by an operator in order to resume normal operations.
          </doc>
        </choice>

        <choice name="invalid-argument" value="542">
          <doc>
            An invalid argument was passed to a command, and the operation could not
            proceed.  An invalid argument is not illegal (see illegal-argument), i.e. it matches
            the domain definition; however the particular value is invalid in this context.
          </doc>
        </choice>
      </enum>
    </domain>

    <!-- - Command: execution.sync - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="sync" code="0x1" label="request notification of completion for issued commands">
      <doc>
        This command is complete when all prior commands are completed.
      </doc>

      <implement role="server" handle="MUST"/>
      <implement role="client" handle="MUST"/>
    </command>

    <!-- - Command: execution.result - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="result" code="0x2" label="carries execution results">
      <doc>
        This command carries data resulting from the execution of a command.
      </doc>

      <implement role="server" handle="MUST"/>
      <implement role="client" handle="MUST"/>

      <field name="command-id" type="sequence-no" required="true"/>
      <field name="value" type="struct32"/>
    </command>

    <!-- - Command: execution.exception  - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="exception" code="0x3" label="notifies a peer of an execution error">
      <doc>
        This command informs a peer of an execution exception. The command-id, when given,
        correlates the error to a specific command.
      </doc>

      <implement role="client" handle="MUST"/>
      <implement role="server" handle="MUST"/>

      <field name="error-code" type="error-code" required="true" label="error code indicating the
        type of error"/>
      <field name="command-id" type="sequence-no" label="exceptional command">
        <doc>
          The command-id of the command which caused the exception. If the exception was not caused
          by a specific command, this value is not set.
        </doc>
      </field>
      <field name="class-code" type="uint8" label="the class code of the command whose execution
        gave rise to the error (if appropriate)"/>
      <field name="command-code" type="uint8" label="the class code of the command whose execution
        gave rise to the error (if appropriate)"/>
      <field name="field-index" type="uint8" label="index of the exceptional field">
        <doc>
          The zero based index of the exceptional field within the arguments to the exceptional
          command. If the exception was not caused by a specific field, this value is not set.
        </doc>
      </field>
      <field name="description" type="str16" label="descriptive text on the exception">
        <doc>
          The description provided is implementation defined, but MUST be in the language
          appropriate for the selected locale.  The intention is that this description is suitable
          for logging or alerting output.
        </doc>
      </field>
      <field name="error-info" type="map" label="map to carry additional information about the
        error"/>

    </command>

  </class>

  <!-- == Class: message ======================================================================= -->

  <class name="message" code="0x4" label="message transfer">
    <doc>
      The message class provides commands that support an industry-standard messaging model.
    </doc>

    <doc type="picture" title="Transfer States">
      START:

        The message has yet to be sent to the recipient.

      NOT-ACQUIRED:

        The message has been sent to the recipient, but is not
        acquired by the recipient.

      ACQUIRED:

        The message has been sent to and acquired by the recipient.

      END:

        The transfer is complete.
    </doc>

    <doc type="picture" title="State Transitions"><![CDATA[
     *:TRANSFER (accept-mode=none)         *:TRANSFER (acquire-mode=pre-acquired)
  +---------------------------------START------------------------------------------+
  |                                   |                                            |
  |                                   | *:TRANSFER (acquire-mode=not-acquired)     |
  |                                   |                                            |
  |                  R:RELEASE       \|/                                           |
  |               +-------------NOT-ACQUIRED<--+                                   |
  |               |               |      |     | R:ACQUIRE (if unavailable)        |
  |               |               |      +-----+                                   |
  |               |               |                                                |
  |               |               | R:ACQUIRE (if available)                       |
  |               |               |                                                |
  |               |              \|/                                               |
  |               |            ACQUIRED<-------------------------------------------+
  |               |               |
  |               |               | R:ACCEPT / R:REJECT / R:RELEASE
  |               |               |
  |               |              \|/
  |               +------------->END]]>
  |                              /|\
  |                               |
  +-------------------------------+
    </doc>

    <doc type="grammar">
      message = *:TRANSFER [ R:ACQUIRE ] [ R:ACCEPT / R:REJECT / R:RELEASE ]
              / *:RESUME
              / *:SET-FLOW-MODE
              / *:FLOW
              / *:STOP
              / C:SUBSCRIBE
              / C:CANCEL
              / C:FLUSH
    </doc>

    <rule name="persistent-message">
      <doc>
        The server SHOULD respect the delivery-mode property of messages and SHOULD make a
        best-effort to hold persistent 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="no-persistent-message-discard">
      <doc>
        The server MUST NOT discard a persistent message in case of a queue overflow.
      </doc>
      <doc type="scenario">
        Create 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="throttling">
      <doc>
        The server MAY use the message.flow command to slow or stop a message publisher when
        necessary.
      </doc>
    </rule>

    <rule name="non-persistent-message-overflow">
      <doc>
        The server MAY overflow non-persistent messages to persistent storage.
      </doc>
    </rule>

    <rule name="non-persistent-message-discard">
      <doc>
        The server MAY discard or dead-letter non-persistent messages on a priority basis if the
        queue size exceeds some configured limit.
      </doc>
    </rule>

    <rule name="min-priority-levels">
      <doc>
        The server MUST implement at least 2 priority levels for messages, where priorities 0 and
        9 are treated as two distinct levels.
      </doc>
    </rule>

    <rule name="priority-level-implementation">
      <doc>
        The server SHOULD implement distinct priority levels in the following manner:
      </doc>
      <doc>
        If the server implements n distinct priorities then priorities 0 to 5 - ceiling(n/2) should
        be treated equivalently and should be the lowest effective priority.  The priorities 4 +
        floor(n/2) should be treated equivalently and should be the highest effective priority. The
        priorities (5 - ceiling(n/2)) to (4 + floor(n/2)) inclusive must be treated as distinct
        priorities.
      </doc>
      <doc>
        Thus, for example, if 2 distinct priorities are implemented, then levels 0 to 4 are
        equivalent, and levels 5 to 9 are equivalent and levels 4 and 5 are distinct.  If 3 distinct
        priorities are implements the 0 to 3 are equivalent, 5 to 9 are equivalent and 3, 4 and 5
        are distinct.
      </doc>
      <doc>
        This scheme ensures that if two priorities are distinct for a server which implements m
        separate priority levels they are also distinct for a server which implements n different
        priority levels where n > m.
      </doc>
    </rule>

    <rule name="priority-delivery">
      <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.
        Subscribe and verify that messages arrive in same order as originally published.
      </doc>
    </rule>

    <role name="server" implement="MUST" />
    <role name="client" implement="MUST" />

    <domain name="destination" type="str8" label="destination for a message">
      <doc>
        Specifies the destination to which the message is to be transferred.
      </doc>
    </domain>

    <domain name="accept-mode" type="uint8" label="indicates a confirmation mode">
      <doc>
        Controls how the sender of messages is notified of successful transfer.
      </doc>

      <enum>
        <choice name="explicit" value="0">
          <doc>
            Successful transfer is signaled by message.accept. An acquired message (whether
            acquisition was implicit as in pre-acquired mode or explicit as in not-acquired mode) is
            not considered transferred until a message.accept that includes the transfer command is
            received.
          </doc>
        </choice>

        <choice name="none" value="1">
          <doc>
            Successful transfer is assumed when accept-mode is "pre-acquired". Messages transferred
            with an accept-mode of "not-acquired" cannot be acquired when accept-mode is "none".
          </doc>
        </choice>
      </enum>
    </domain>

    <domain name="acquire-mode" type="uint8" label="indicates the transfer mode">
      <doc>
        Indicates whether a transferred message can be considered as automatically acquired or
        whether an explicit request is necessary in order to acquire it.
      </doc>

      <enum>
        <choice name="pre-acquired" value="0">
          <doc>
            the message is acquired when the transfer starts
          </doc>
        </choice>

        <choice name="not-acquired" value="1">
          <doc>
            the message is not acquired when it arrives, and must be explicitly acquired by the
            recipient
          </doc>
        </choice>
      </enum>
    </domain>

    <domain name="reject-code" type="uint16" label="reject code for transfer">
      <doc>
        Code specifying the reason for a message reject.
      </doc>
      <enum>
        <choice name="unspecified" value="0">
          <doc>
            Rejected for an unspecified reason.
          </doc>
        </choice>
        <choice name="unroutable" value="1">
          <doc>
            Delivery was attempted but there were no queues which the message could be routed to.
          </doc>
        </choice>
        <choice name="immediate" value="2">
          <doc>
            The rejected message had the immediate flag set to true, but at the time of the transfer
            at least one of the queues to which it was to be routed did not have any subscriber able
            to take the message.
          </doc>
        </choice>
      </enum>
    </domain>

    <domain name="resume-id" type="str16">
      <doc>
        A resume-id serves to identify partially transferred message content. The id is chosen by
        the sender, and must be unique to a given user. A resume-id is not expected to be unique
        across users.
      </doc>
    </domain>

    <domain name="delivery-mode" type="uint8"
            label="indicates whether a message should be treated as transient or durable">
     <doc>

        Used to set the reliability requirements for a message which is transferred to the server.
      </doc>
      <enum>
        <choice name="non-persistent" value="1">
          <doc>
            A non-persistent message may be lost in event of a failure, but the nature of the
            communication is such that an occasional message loss is tolerable. This is the lowest
            overhead mode. Non-persistent messages are delivered at most once only.
          </doc>
        </choice>

        <choice name="persistent" value="2">
          <doc>
            A persistent message is one which must be stored on a persistent medium (usually hard
            drive) at every stage of delivery so that it will not be lost in event of failure (other
            than of the medium itself). This is normally accomplished with some additional overhead.
            A persistent message may be delivered more than once if there is uncertainty about the
            state of its delivery after a failure and recovery.
          </doc>
        </choice>
      </enum>
    </domain>

    <domain name="delivery-priority" type="uint8"
      label="indicates the desired priority to assign to a message transfer">
      <doc>
        Used to assign a priority to a message transfer. Priorities range from 0 (lowest) to 9
        (highest).
      </doc>
      <enum>
        <choice name="lowest" value="0">
          <doc>
            Lowest possible priority message.
          </doc>
        </choice>

        <choice name="lower" value="1">
          <doc>
            Very low priority message
          </doc>
        </choice>

        <choice name="low" value="2">
          <doc>
            Low priority message.
          </doc>
        </choice>

        <choice name="below-average" value="3">
          <doc>
            Below average priority message.
          </doc>
        </choice>

        <choice name="medium" value="4">
          <doc>
            Medium priority message.
          </doc>
        </choice>


        <choice name="above-average" value="5">
          <doc>
            Above average priority message
          </doc>
        </choice>


        <choice name="high" value="6">
          <doc>
            High priority message
          </doc>
        </choice>

        <choice name="higher" value="7">
          <doc>
            Higher priority message
          </doc>
        </choice>

        <choice name="very-high" value="8">
          <doc>
            Very high priority message.
          </doc>
        </choice>

        <choice name="highest" value="9">
          <doc>
            Highest possible priority message.
          </doc>
        </choice>
      </enum>
    </domain>

    <struct name="delivery-properties" size="4" code="0x1" pack="2">
      <field name="discard-unroutable" type="bit" label="controls discard of unroutable messages">
        <doc>
          If set on a message that is not routable the broker can discard it. If not set, an
          unroutable message should be handled by reject when accept-mode is explicit; or by routing
          to the alternate-exchange if defined when accept-mode is none.
        </doc>
      </field>

      <field name="immediate" type="bit" label="Consider message unroutable if it cannot be
        processed immediately">
        <doc>
          If the immediate flag is set to true on a message transferred to a Server, then the
          message should be considered unroutable (and not delivered to any queues) if, for any
          queue that it is to be routed to according to the standard routing behavior, there is not
          a subscription on that queue able to receive the message. The treatment of unroutable
          messages is dependent on the value of the discard-unroutable flag.
        </doc>
        <doc>
          The immediate flag is ignored on transferred to a Client.
        </doc>
      </field>

      <field name="redelivered" type="bit" label="redelivery flag">
        <doc>
          This boolean flag indicates that the message may have been previously delivered to this
          or another client.
        </doc>
        <doc>
          If the redelivered flag is set on transfer to a Server, then any delivery of the message
          from that Server to a Client must also have the redelivered flag set to true.
        </doc>
        <rule name="implementation">
          <doc>
            The server MUST try to signal redelivered messages when it can. When redelivering a
            message that was not successfully accepted, the server SHOULD deliver it to the original
            client if possible.
          </doc>
          <doc type="scenario">
            Create a shared queue and publish a message to the queue. Subscribe using explicit
            accept-mode, but do not accept the message. Close the session, reconnect, and subscribe
            to the queue again. The message MUST arrive with the redelivered flag set.
          </doc>
        </rule>
        <rule name="hinting">
          <doc>
            The client should not rely on the redelivered field to detect duplicate messages where
            publishers may themselves produce duplicates. A fully robust client should be able to
            track duplicate received messages on non-transacted, and locally-transacted sessions.
          </doc>
        </rule>
      </field>

      <field name="priority" type="delivery-priority" label="message priority, 0 to 9"
        required="true">
        <doc> Message priority, which can be between 0 and 9. Messages with higher priorities may be
          delivered before those with lower priorities. </doc>
      </field>

      <field name="delivery-mode" type="delivery-mode" label="message persistence requirement"
        required="true">
        <doc> The delivery mode may be non-persistent or persistent. </doc>
      </field>

      <field name="ttl" type="uint64" label="time to live in ms">
        <doc> Duration in milliseconds for which the message should be considered "live". If this is
          set then a message expiration time will be computed based on the current time plus this
          value. Messages that live longer than their expiration time will be discarded (or dead
          lettered).</doc>
        <rule name="ttl-decrement">
          <doc>
            If a message is transferred between brokers before delivery to a final subscriber the
            ttl should be decremented before peer to peer transfer and both timestamp and expiration
            should be cleared.
          </doc>
        </rule>
      </field>

      <field name="timestamp" type="datetime" label="message timestamp">
        <doc>
          The timestamp is set by the broker on arrival of the message.
        </doc>
      </field>

      <field name="expiration" type="datetime" label="message expiration time">
        <doc>
          The expiration header assigned by the broker. After receiving the message the broker sets
          expiration to the sum of the ttl specified in the publish command and the current time.
          (ttl=expiration - timestamp)
        </doc>
      </field>

      <field name="exchange" type="exchange.name" label="originating exchange">
        <doc>
          Identifies the exchange specified in the destination field of the message.transfer used to
          publish the message. This MUST be set by the broker upon receipt of a message.
        </doc>
      </field>

      <field name="routing-key" type="str8" label="message routing key">
        <doc>
          The value of the key determines to which queue the exchange will send the message. The way
          in which keys are used to make this routing decision depends on the type of exchange to
          which the message is sent. For example, a direct exchange will route a message to a queue
          if that queue is bound to the exchange with a binding-key identical to the routing-key of
          the message.
        </doc>
      </field>

      <field name="resume-id" type="resume-id" label="global id for message transfer">
        <doc>
          When a resume-id is provided the recipient MAY use it to retain message data should the
          session expire while the message transfer is still incomplete.
        </doc>
      </field>

      <field name="resume-ttl" type="uint64" label="ttl in ms for interrupted message data">
        <doc>
          When a resume-ttl is provided the recipient MAY use it has a guideline for how long to
          retain the partially complete data when a resume-id is specified. If no resume-id is
          specified then this value should be ignored.
        </doc>
      </field>
    </struct>

    <struct name="fragment-properties" size="4" code="0x2" pack="2">
      <doc>
        These properties permit the transfer of message fragments. These may be used in conjunction
        with byte level flow control to limit the rate at which large messages are received. Only
        the first fragment carries the delivery-properties and message-properties.

        Syntactically each fragment appears as a complete message to the lower layers of the
        protocol, however the model layer is required to treat all the fragments as a single
        message. For example all fragments must be delivered to the same client. In pre-acquired
        mode, no message fragments can be delivered by the broker until the entire message has been
        received.
      </doc>

      <field name="first" type="bit" default="1">
        <doc>True if this fragment contains the start of the message, false otherwise.</doc>
      </field>

      <field name="last" type="bit" default="1">
        <doc>True if this fragment contains the end of the message, false otherwise.</doc>
      </field>

      <field name="fragment-size" type="uint64">
        <doc>This field may optionally contain the size of the fragment.</doc>
      </field>
    </struct>

    <struct name="reply-to" size="2" pack="2">
      <doc>The reply-to domain provides a simple address structure for replying to to a message to a
      destination within the same virtual-host.</doc>
      <field name="exchange" type="exchange.name" label="the name of the exchange to reply to"/>
      <field name="routing-key" type="str8" label="the routing-key to use when replying"/>
    </struct>

    <struct name="message-properties" size="4" code="0x3" pack="2">
      <field name="content-length" type="uint64" label="length of the body segment in bytes">
        <doc>
          The length of the body segment in bytes.
        </doc>
      </field>

      <field name="message-id" type="uuid" label="application message identifier">
        <doc>
          Message-id is an optional property of UUID type which uniquely identifies a message within
          the message system. The message producer is usually responsible for setting the
          message-id. The server MAY discard a message as a duplicate if the value of the message-id
          matches that of a previously received message. Duplicate messages MUST still be accepted
          if transferred with an accept-mode of "explicit".
        </doc>

        <rule name="unique">
          <doc>
            A message-id MUST be unique within a given server instance. A message-id SHOULD be
            globally unique (i.e. across different systems).
          </doc>
        </rule>

        <rule name="immutable">
          <doc>
            A message ID is immutable. Once set, a message-id MUST NOT be changed or reassigned,
            even if the message is replicated, resent or sent to multiple queues.
          </doc>
        </rule>
      </field>

      <field name="correlation-id" type="vbin16" label="application correlation identifier">
        <doc>
          This is a client-specific id that may be used to mark or identify messages between
          clients. The server ignores this field.
        </doc>
      </field>

      <field name="reply-to" type="reply-to" label="destination to reply to">
        <doc>
          The destination of any message that is sent in reply to this message.
        </doc>
      </field>

      <field name="content-type" type="str8" label="MIME content type">
        <doc>
          The RFC-2046 MIME type for the message content (such as "text/plain"). This is set by the
          originating client.
        </doc>
      </field>

      <field name="content-encoding" type="str8" label="MIME content encoding">
        <doc>
          The encoding for character-based message content. This is set by the originating client.
          Examples include UTF-8 and ISO-8859-15.
        </doc>
      </field>

      <field name="user-id" type="vbin16" label="creating user id">
        <doc>
          The identity of the user responsible for producing the message. The client sets this
          value, and it is authenticated by the broker.
        </doc>

        <rule name="authentication">
          <doc>
            The server MUST produce an unauthorized-access exception if the user-id field is set to
            a principle for which the client is not authenticated.
          </doc>
        </rule>
      </field>

      <field name="app-id" type="vbin16" label="creating application id">
        <doc>
          The identity of the client application responsible for producing the message.
        </doc>
      </field>

      <field name="application-headers" type="map" label="application specific headers table">
        <doc>
          This is a collection of user-defined headers or properties which may be set by the
          producing client and retrieved by the consuming client.
        </doc>
      </field>
    </struct>

    <domain name="flow-mode" type="uint8" label="the flow-mode for allocating flow credit">
      <enum>
        <choice name="credit" value="0">
          <doc>
            Credit based flow control.
          </doc>
        </choice>

        <choice name="window" value="1">
          <doc>
            Window based flow control.
          </doc>
        </choice>
      </enum>
    </domain>

    <domain name="credit-unit" type="uint8" label="specifies the unit of credit balance">
      <enum>
        <choice name="message" value="0">
          <doc>Indicates a value specified in messages.</doc>
        </choice>
        <choice name="byte" value="1">
          <doc>Indicates a value specified in bytes.</doc>
        </choice>
      </enum>
    </domain>

    <!-- - Command: message.transfer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="transfer" code="0x1" label="transfer a message">
      <doc>
        This command transfers a message between two peers. When a client uses this command to
        publish a message to a broker, the destination identifies a specific exchange. The message
        will then be routed to queues as defined by the exchange configuration.

        The client may request a broker to transfer messages to it, from a particular queue, by
        issuing a subscribe command. The subscribe command specifies the destination that the broker
        should use for any resulting transfers.
      </doc>

      <rule name="transactional-publish">
        <doc>
          If a transfer to an exchange occurs within a transaction, then it is not available from
          the queue until the transaction commits. It is not specified whether routing takes place
          when the transfer is received or when the transaction commits.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />


      <field name="destination" type="destination" label="message destination">
        <doc>
          Specifies the destination to which the message is to be transferred.
        </doc>

        <rule name="blank-destination">
          <doc>
            The server MUST accept a blank destination to mean the default exchange.
          </doc>
        </rule>

        <exception name="nonexistent-exchange" error-code="not-found">
          <doc>
            If the destination refers to an exchange that does not exist, the peer MUST raise a
            session exception.
          </doc>
        </exception>
      </field>

      <field name="accept-mode" type="accept-mode" required="true">
        <doc>
          Indicates whether message.accept, session.complete, or nothing at all is required to
          indicate successful transfer of the message.
        </doc>
      </field>

      <field name="acquire-mode" type="acquire-mode" required="true">
        <doc>
          Indicates whether or not the transferred message has been acquired.
        </doc>
      </field>

      <segments>
        <header>
          <entry type="delivery-properties"/>
          <entry type="fragment-properties"/>
          <entry type="message-properties"/>
        </header>
        <body/>
      </segments>
    </command>

    <!-- - Command: message.accept - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="accept" code="0x2" label="reject a message">
      <doc>
        Accepts the message. Once a transfer is accepted, the command-id may no longer be referenced
        from other commands.
      </doc>

      <rule name="acquisition">
        <doc>
          The recipient MUST have acquired a message in order to accept it.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <field name="transfers" type="session.commands" required="true">
        <doc>
          Identifies the messages previously transferred that should be accepted.
        </doc>
      </field>
    </command>

    <!-- - Command: message.reject - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="reject" code="0x3" label="reject a message">
      <doc>
        Indicates that the message transfers are unprocessable in some way. A server may reject a
        message if it is unroutable. A client may reject a message if it is invalid. A message may
        be rejected for other reasons as well. Once a transfer is rejected, the command-id may no
        longer be referenced from other commands.
      </doc>

      <rule name="alternate-exchange">
        <doc>
          When a client rejects a message, the server MUST deliver that message to the
          alternate-exchange on the queue from which it was delivered. If no alternate-exchange is
          defined for that queue the broker MAY discard the message.
        </doc>
      </rule>

      <rule name="acquisition">
        <doc>
          The recipient MUST have acquired a message in order to reject it. If the message is not
          acquired any reject MUST be ignored.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <field name="transfers" type="session.commands" required="true">
        <doc>
          Identifies the messages previously transferred that should be rejected.
        </doc>
      </field>
      <field name="code" type="reject-code" required="true">
        <doc>
          Code describing the reason for rejection.
        </doc>
      </field>
      <field name="text" type="str8" label="informational text for message reject">
        <doc>
          Text describing the reason for rejection.
        </doc>
      </field>
    </command>

    <!-- - Command: message.release  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="release" code="0x4" label="release a message">
      <doc>
        Release previously transferred messages. When acquired messages are released, they become
        available for acquisition by any subscriber. Once a transfer is released, the command-id may
        no longer be referenced from other commands.
      </doc>

      <rule name="ordering">
        <doc>
          Acquired messages that have been released MAY subsequently be delivered out of order.
          Implementations SHOULD ensure that released messages keep their position with respect to
          undelivered messages of the same priority.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MAY" />

      <field name="transfers" type="session.commands" required="true">
        <doc>
          Indicates the messages to be released.
        </doc>
      </field>
      <field name="set-redelivered" type="bit" label="mark the released messages as redelivered">
        <doc>
          By setting set-redelivered to true, any acquired messages released to a queue with this
          command will be marked as redelivered on their next transfer from that queue. If this flag
          is not set, then an acquired message will retain its original redelivered status on the
          queue. Messages that are not acquired are unaffected by the value of this flag.
        </doc>
      </field>
    </command>

    <!-- - Command: message.acquire  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="acquire" code="0x5" label="acquire messages for consumption">
      <doc>
        Acquires previously transferred messages for consumption. The acquired ids (if any) are
        sent via message.acquired.
      </doc>

      <rule name="one-to-one">
        <doc>
          Each acquire MUST produce exactly one message.acquired even if it is empty.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />

      <field name="transfers" type="session.commands" required="true">
        <doc>
          Indicates the messages to be acquired.
        </doc>
      </field>

      <result>
        <struct name="acquired" size="4" code="0x4" pack="2" label="indicates acquired messages">
          <doc>
            Identifies a set of previously transferred messages that have now been acquired.
          </doc>

          <field name="transfers" type="session.commands" required="true">
            <doc>
              Indicates the acquired messages.
            </doc>
          </field>
        </struct>
      </result>
    </command>

    <!-- - Command: message.resume - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="resume" code="0x6" label="resume an interrupted message transfer">
      <doc>
        This command resumes an interrupted transfer. The recipient should return the amount of
        partially transferred data associated with the given resume-id, or zero if there is no data
        at all. If a non-zero result is returned, the recipient should expect to receive message
        fragment(s) containing the remainder of the interrupted message.
      </doc>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <field name="destination" type="destination">
        <doc>
          The destination to which the remaining message fragments are transferred.
        </doc>

        <exception name="destination-not-found" error-code="not-found">
          <doc>If the destination does not exist, the recipient MUST close the session.</doc>
        </exception>
      </field>

      <field name="resume-id" type="resume-id" required="true">
        <doc>
          The name of the transfer being resumed.
        </doc>

        <rule name="unknown-resume-id">
          <doc>If the resume-id is not known, the recipient MUST return an offset of zero.</doc>
        </rule>
      </field>

      <result>
        <struct name="message-resume-result" size="4" code="0x5" pack="2">
          <field name="offset" type="uint64">
            <doc>
              Indicates the amount of data already transferred.
            </doc>
          </field>
        </struct>
      </result>
    </command>

    <!-- - Command: message.subscribe  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="subscribe" code="0x7" label="start a queue subscription">
      <doc> This command asks the server to start a "subscription", which is a request for messages
        from a specific queue. Subscriptions last as long as the session they were created on, or
        until the client cancels them. </doc>

      <rule name="simultaneous-subscriptions">
        <doc> The server SHOULD support at least 16 subscriptions per queue, and ideally, impose no
          limit except as defined by available resources. </doc>
        <doc type="scenario"> Create a queue and create subscriptions on that queue until the server
          closes the connection. Verify that the number of subscriptions created was at least
          sixteen and report the total number. </doc>
      </rule>

      <rule name="default-flow-mode">
        <doc> The default flow mode for new subscriptions is window-mode. </doc>
      </rule>

      <exception name="queue-deletion" error-code="resource-deleted">
        <doc>
          If the queue for this subscription is deleted, any subscribing sessions MUST be closed.
          This exception may occur at any time after the subscription has been completed.
        </doc>
      </exception>

      <exception name="queue-not-found" error-code="not-found">
        <doc> If the queue for this subscription does not exist, then the subscribing session MUST
          be closed. </doc>
      </exception>

      <rule name="initial-credit">
        <doc>
          Immediately after a subscription is created, the initial byte and message credit for that
          destination is zero.
        </doc>
      </rule>

      <implement role="server" handle="MUST"/>

      <field name="queue" type="queue.name" required="true">
        <doc> Specifies the name of the subscribed queue. </doc>
      </field>

      <field name="destination" type="destination" label="incoming message destination">
        <doc> The client specified name for the subscription. This is used as the destination for
          all messages transferred from this subscription. The destination is scoped to the session.
        </doc>

        <exception name="unique-subscriber-destination" error-code="not-allowed">
          <doc> The client MUST NOT specify a destination that refers to an existing subscription on
            the same session. </doc>
          <doc type="scenario"> Attempt to create two subscriptions on the same session with the
            same non-empty destination. </doc>
        </exception>
      </field>

      <field name="accept-mode" type="accept-mode" required="true">
        <doc> The accept-mode to use for messages transferred from this subscription. </doc>
      </field>

      <field name="acquire-mode" type="acquire-mode" required="true">
        <doc> The acquire-mode to use for messages transferred from this subscription. </doc>
      </field>

      <field name="exclusive" type="bit" label="request exclusive access">
        <doc> Request an exclusive subscription. This prevents other subscribers from subscribing to
          the queue. </doc>

        <exception name="in-use" error-code="resource-locked">
          <doc> The server MUST NOT grant an exclusive subscription to a queue that already has
            subscribers. </doc>
          <doc type="scenario"> Open two connections to a server, and in one connection create a
            shared (non-exclusive) queue and then subscribe to the queue. In the second connection
            attempt to subscribe to the same queue using the exclusive option. </doc>
        </exception>
      </field>

      <field name="resume-id" type="resume-id">
        <doc> Requests that the broker use the supplied resume-id when transferring messages for
          this subscription. </doc>
      </field>

      <field name="resume-ttl" type="uint64">
        <doc> Requested duration in milliseconds for the broker use as resume-ttl when transferring
          messages for this subscription. </doc>
      </field>

      <field name="arguments" type="map" label="arguments for vendor extensions">
        <doc> The syntax and semantics of these arguments depends on the providers implementation.
        </doc>
      </field>
    </command>

    <!-- - Command: message.cancel - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="cancel" code="0x8" label="end a queue subscription">
      <doc>
        This command cancels a subscription. This does not affect already delivered messages, but it
        does mean the server will not send any more messages for that subscription. The client may
        receive an arbitrary number of messages in between sending the cancel command and receiving
        notification that the cancel command is complete.
      </doc>

      <rule name="post-cancel-transfer-resolution">
        <doc>
          Canceling a subscription MUST NOT affect pending transfers. A transfer made prior to
          canceling transfers to the destination MUST be able to be accepted, released, acquired, or
          rejected after the subscription is canceled.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />

      <field name="destination" type="destination" required="true">
        <exception name="subscription-not-found" error-code="not-found">
          <doc>
            If the subscription specified by the destination is not found, the server MUST close the
            session.
          </doc>
        </exception>
      </field>
    </command>

    <!-- - Command: message.set-flow-mode  - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="set-flow-mode" code="0x9" label="set the flow control mode">
      <doc>
        Sets the mode of flow control used for a given destination to either window or credit based
        flow control.

        With credit based flow control, the sender of messages continually maintains its current
        credit balance with the recipient. The credit balance consists of two values, a message
        count, and a byte count. Whenever message data is sent, both counts must be decremented.
        If either value reaches zero, the flow of message data must stop. Additional credit is
        received via the message.flow command.

        The sender MUST NOT send partial assemblies. This means that if there is not enough byte
        credit available to send a complete message, the sender must either wait or use message
        fragmentation (see the fragment-properties header struct) to send the first part of the
        message data in a complete assembly.

        Window based flow control is identical to credit based flow control, however message
        transfer completion implicitly grants a single unit of message credit, and the size of the
        message in byte credits for each completed message transfer. Completion of the transfer
        command with session.completed is the only way credit is implicitly updated; message.accept,
        message.release, message.reject, tx.commit and tx.rollback have no effect on the outstanding
        credit balances.
      </doc>

      <rule name="byte-accounting">
        <doc>
          The byte count is decremented by the payload size of each transmitted frame with segment
          type header or body appearing within a message.transfer command. Note that the payload
          size is the frame size less the frame header size.
        </doc>
      </rule>

      <rule name="mode-switching">
        <doc>
          Mode switching may only occur if both the byte and message credit balance are zero. There
          are three ways for a recipient of messages to be sure that the sender's credit balances
          are zero:

            1) The recipient may send a message.stop command to the sender. When the recipient
               receives notification of completion for the message.stop command, it knows that the
               sender's credit is zero.

            2) The recipient may perform the same steps described in (1) with the message.flush
               command substituted for the message.stop command.

            3) Immediately after a subscription is created with message.subscribe, the credit for
               that destination is zero.
        </doc>
      </rule>

      <rule name="default-flow-mode">
        <doc>
          Prior to receiving an explicit set-flow-mode command, a peer MUST consider the flow-mode
          to be window.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <field name="destination" type="destination"/>
      <field name="flow-mode" type="flow-mode" required="true">
        <doc>
          The new flow control mode.
        </doc>
      </field>
    </command>

    <!-- - Command: message.flow - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="flow" code="0xa" label="control message flow">
      <doc>
        This command controls the flow of message data to a given destination. It is used by the
        recipient of messages to dynamically match the incoming rate of message flow to its
        processing or forwarding capacity. Upon receipt of this command, the sender must add "value"
        number of the specified unit to the available credit balance for the specified destination.
        A value of (0xFFFFFFFF) indicates an infinite amount of credit. This disables any limit for
        the given unit until the credit balance is zeroed with message.stop or message.flush.
      </doc>

      <!-- throws no-such-destination -->

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <field name="destination" type="destination"/>
      <field name="unit" type="credit-unit" required="true">
        <doc>
          The unit of value.
        </doc>
      </field>
      <field name="value" type="uint32">
        <doc>
          If the value is not set then this indicates an infinite amount of credit.
        </doc>
      </field>
    </command>

    <!-- - Command: message.flush  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="flush" code="0xb" label="force the sending of available messages">
      <doc>
        Forces the sender to exhaust his credit supply. The sender's credit will always be zero when
        this command completes. The command completes when immediately available message data has
        been transferred, or when the credit supply is exhausted.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="destination" type="destination"/>
    </command>

    <!-- - Command: message.stop - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="stop" code="0xc" label="stop the sending of messages">
      <doc>
        On receipt of this command, a producer of messages MUST set his credit to zero for the given
        destination. When notifying of completion, credit MUST be zero and no further messages will
        be sent until such a time as further credit is received.
      </doc>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <field name="destination" type="destination"/>
    </command>

  </class>

  <!-- == Class: tx ============================================================================ -->

  <class name="tx" code="0x5" label="work with standard transactions">
    <doc>
      Standard transactions provide so-called "1.5 phase commit". We can ensure that work is never
      lost, but there is a chance of confirmations being lost, so that messages may be resent.
      Applications that use standard transactions must be able to detect and ignore duplicate
      messages.
    </doc>

    <doc type="grammar">
      tx  = C:SELECT
          / C:COMMIT
          / C:ROLLBACK
    </doc>

    <!-- XXX: this isn't really a rule, as stated there is no way for
              a client library to implement this -->
    <rule name="duplicate-tracking">
      <doc>
        An client using standard transactions SHOULD be able to track all messages received within a
        reasonable period, and thus detect and reject duplicates of the same message. It SHOULD NOT
        pass these to the application layer.
      </doc>
    </rule>

    <role name="server" implement="SHOULD" />

    <!-- - Command: tx.select  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="select" code="0x1" label="select standard transaction mode">
      <doc>
        This command sets the session to use standard transactions. The client must use this command
        exactly once on a session before using the Commit or Rollback commands.
      </doc>

      <exception name="exactly-once" error-code="illegal-state">
        <doc>
          A client MUST NOT select standard transactions on a session that is already transactional.
        </doc>
      </exception>

      <exception name="no-dtx" error-code="illegal-state">
        <doc>
          A client MUST NOT select standard transactions on a session that is already enlisted in a
          distributed transaction.
        </doc>
      </exception>

      <exception name="explicit-accepts" error-code="not-allowed">
        <doc>
          On a session on which tx.select has been issued, a client MUST NOT issue a
          message.subscribe command with the accept-mode property set to any value other than
          explicit. Similarly a tx.select MUST NOT be issued on a session on which a there is a non
          cancelled subscriber with accept-mode of none.
        </doc>
      </exception>

      <implement role="server" handle="MUST" />
    </command>

    <!-- - Command: tx.commit  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="commit" code="0x2" label="commit the current transaction">
      <doc>
        This command commits all messages published and accepted in the current transaction. A
        new transaction starts immediately after a commit.
      </doc>
      <doc>
        In more detail, the commit acts on all messages which have been transferred from the Client
        to the Server, and on all acceptances of messages sent from Server to Client.  Since the
        commit acts on commands sent in the same direction as the commit command itself, there is no
        ambiguity on the scope of the commands being committed.  Further, the commit will not be
        completed until all preceding commands which it affects have been completed.
      </doc>
      <doc>
        Since transactions act on explicit accept commands, the only valid accept-mode for message
        subscribers is explicit.  For transferring messages from Client to Server (publishing) all
        accept-modes are permitted.
      </doc>

      <exception name="select-required" error-code="illegal-state">
        <doc>
          A client MUST NOT issue tx.commit on a session that has not been selected for standard
          transactions with tx.select.
        </doc>
      </exception>



      <implement role="server" handle="MUST" />
    </command>

    <!-- - Command: tx.rollback  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="rollback" code="0x3" label="abandon the current transaction">
      <doc>
        This command abandons the current transaction.  In particular the transfers from Client to
        Server (publishes) and accepts of transfers from Server to Client which occurred in the
        current transaction are discarded.  A new transaction starts immediately after a rollback.
      </doc>
      <doc>
        In more detail, when a rollback is issued, any the effects of transfers which occurred from
        Client to Server are discarded.  The Server will issue completion notification for all such
        transfers prior to the completion of the rollback.  Similarly the effects of any
        message.accept issued from Client to Server prior to the issuance of the tx.rollback will be
        discarded; and notification of completion for all such commands will be issued before the
        issuance of the completion for the rollback.
      </doc>
      <doc>
        After the completion of the rollback, the client will still hold the messages which it has
        not yet accepted (including those for which accepts were previously issued within the
        transaction); i.e. the messages remain "acquired".  If the Client wishes to release those
        messages back to the Server, then appropriate message.release commands must be issued.
      </doc>

      <exception name="select-required" error-code="illegal-state">
        <doc>
          A client MUST NOT issue tx.rollback on a session that has not been selected for standard
          transactions with tx.select.
        </doc>
      </exception>

      <implement role="server" handle="MUST" />
    </command>

  </class>

  <!-- == Class: dtx =========================================================================== -->

  <class name="dtx" code="0x6" label="Demarcates dtx branches">
    <doc>
      This provides the X-Open XA distributed transaction protocol support. It allows a session
      to be selected for use with distributed transactions, the transactional boundaries for work on
      that session to be demarcated and allows the transaction manager to coordinate transaction
      outcomes.
    </doc>

    <doc type="grammar">
      dtx-demarcation = C:SELECT *demarcation
      demarcation     = C:START C:END
    </doc>

    <doc type="grammar">
      dtx-coordination    = *coordination
      coordination        = command
                            / outcome
                            / recovery
      command             = C:SET-TIMEOUT
                            / C:GET-TIMEOUT
      outcome             = one-phase-commit
                            / one-phase-rollback
                            / two-phase-commit
                            / two-phase-rollback
      one-phase-commit    = C:COMMIT
      one-phase-rollback  = C:ROLLBACK
      two-phase-commit    = C:PREPARE C:COMMIT
      two-phase-rollback  = C:PREPARE C:ROLLBACK
      recovery            = C:RECOVER *recovery-outcome
      recovery-outcome    = one-phase-commit
                            / one-phase-rollback
                            / C:FORGET

    </doc>

    <rule name="transactionality">
      <doc>
        Enabling XA transaction support on a session requires that the server MUST manage
        transactions demarcated by start-end blocks. That is to say that on this XA-enabled session,
        work undergone within transactional blocks is performed on behalf a transaction branch
        whereas work performed outside of transactional blocks is NOT transactional.
      </doc>
    </rule>

    <role name="server" implement="MAY" />
    <role name="client" implement="MAY" />

    <!-- XA domains -->

    <domain name="xa-status" type="uint16" label="XA return codes">
      <enum>
        <choice name="xa-ok" value="0">
          <doc>
            Normal execution completion (no error).
          </doc>
        </choice>

        <choice name="xa-rbrollback" value="1">
          <doc>
            The rollback was caused for an unspecified reason.
          </doc>
        </choice>

        <choice name="xa-rbtimeout" value="2">
          <doc>
            A transaction branch took too long.
          </doc>
        </choice>

        <choice name="xa-heurhaz" value="3">
          <doc>
            The transaction branch may have been heuristically completed.
          </doc>
        </choice>

        <choice name="xa-heurcom" value="4">
          <doc>
            The transaction branch has been heuristically committed.
          </doc>
        </choice>

        <choice name="xa-heurrb" value="5">
          <doc>
            The transaction branch has been heuristically rolled back.
          </doc>
        </choice>

        <choice name="xa-heurmix" value="6">
          <doc>
            The transaction branch has been heuristically committed and rolled back.
          </doc>
        </choice>

        <choice name="xa-rdonly" value="7">
          <doc>
            The transaction branch was read-only and has been committed.
          </doc>
        </choice>
      </enum>
    </domain>

    <struct name="xa-result" size="4" code="0x1" pack="2">
      <field name="status" type="xa-status" required="true"/>
    </struct>

    <!-- Struct for xid -->

    <struct name="xid" size="2" pack="2" label="dtx branch identifier">
      <doc>
        An xid uniquely identifies a transaction branch.
      </doc>

      <field name="format" type="uint32" label="implementation specific format code"
        required="true"/>
      <field name="global-id" type="vbin8" label="global transaction id" required="true"/>
      <field name="branch-id" type="vbin8" label="branch qualifier" required="true"/>
    </struct>

    <!-- - Command: dtx.select - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="select" code="0x1" label="Select dtx mode">
      <doc>
        This command sets the session to use distributed transactions. The client must use this
        command at least once on a session before using XA demarcation operations.
      </doc>

      <implement role="server" handle="MAY" />
    </command>

    <!-- - Command: dtx.start  - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="start" code="0x2" label="Start a dtx branch">
      <doc>
        This command is called when messages should be produced and consumed on behalf a transaction
        branch identified by xid.
      </doc>

      <exception name="illegal-state" error-code="illegal-state">
        <doc>
          If the command is invoked in an improper context (see class grammar) then the server MUST
          send a session exception.
        </doc>
      </exception>

      <exception name="already-known" error-code="not-allowed">
        <doc>
          If neither join nor resume is specified is specified and the transaction branch specified
          by xid has previously been seen then the server MUST raise an exception.
        </doc>
      </exception>

      <exception name="join-and-resume" error-code="not-allowed">
        <doc>
          If join and resume are specified then the server MUST raise an exception.
        </doc>
      </exception>

      <implement role="server" handle="MAY" />

      <field name="xid" type="xid" label="Transaction xid" required="true">
        <doc>
          Specifies the xid of the transaction branch to be started.
        </doc>

        <exception name="unknown-xid" error-code="not-allowed">
          <doc>
            If xid is already known by the broker then the server MUST raise an exception.
          </doc>
        </exception>
      </field>

      <field name="join" type="bit" label="Join with existing xid flag">
        <doc>
          Indicate whether this is joining an already associated xid. Indicate that the start
          applies to joining a transaction previously seen.
        </doc>

        <exception name="unsupported" error-code="not-implemented">
          <doc>
            If the broker does not support join the server MUST raise an exception.
          </doc>
        </exception>
      </field>

      <field name="resume" type="bit" label="Resume flag">
        <doc>
          Indicate that the start applies to resuming a suspended transaction branch specified.
        </doc>
      </field>

      <result type="xa-result">
        <doc>
          This confirms to the client that the transaction branch is started or specify the error
          condition.

          The value of this field may be one of the following constants:

          xa-ok: Normal execution.

          xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
              reason.

          xa-rbtimeout: The work represented by this transaction branch took too long.
        </doc>
      </result>
    </command>

    <!-- - Command: dtx.end  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="end" code="0x3" label="End a dtx branch">
      <doc>
        This command is called when the work done on behalf a transaction branch finishes or needs
        to be suspended.
      </doc>

      <exception name="illegal-state" error-code="illegal-state">
        <doc>
          If the command is invoked in an improper context (see class grammar) then the server MUST
          raise an exception.
        </doc>
      </exception>

      <exception name="suspend-and-fail" error-code="not-allowed">
        <doc>
          If suspend and fail are specified then the server MUST raise an exception.
        </doc>
      </exception>

      <rule name="success">
        <doc>
          If neither fail nor suspend are specified then the portion of work has completed
          successfully.
        </doc>
      </rule>

      <rule name="session-closed">
        <doc>
          When a session is closed then the currently associated transaction branches MUST be marked
          rollback-only.
        </doc>
      </rule>

      <implement role="server" handle="MAY" />

      <field name="xid" type="xid" label="Transaction xid" required="true">
        <doc>
          Specifies the xid of the transaction branch to be ended.
        </doc>

        <exception name="not-associated" error-code="illegal-state">
          <doc>
            The session MUST be currently associated with the given xid (through an earlier start
            call with the same xid).
          </doc>
        </exception>
      </field>

      <field name="fail" type="bit" label="Failure flag">
        <doc>
          If set, indicates that this portion of work has failed; otherwise this portion of work has
          completed successfully.
        </doc>

        <rule name="failure">
          <doc>
            An implementation MAY elect to roll a transaction back if this failure notification is
            received. Should an implementation elect to implement this behavior, and this bit is
            set, then then the transaction branch SHOULD be marked as rollback-only and the end
            result SHOULD have the xa-rbrollback status set.
          </doc>
        </rule>
      </field>

      <field name="suspend" type="bit" label="Temporary suspension flag">
        <doc>
          Indicates that the transaction branch is temporarily suspended in an incomplete state.
        </doc>

        <rule name="resume">
          <doc>
            The transaction context is in a suspended state and must be resumed via the start
            command with resume specified.
          </doc>
        </rule>

      </field>

      <result type="xa-result">
        <doc>
          This command confirms to the client that the transaction branch is ended or specify the
          error condition.

          The value of this field may be one of the following constants:

          xa-ok: Normal execution.

          xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
              reason. If an implementation chooses to implement rollback-on-failure behavior, then
              this value should be selected if the dtx.end.fail bit was set.

          xa-rbtimeout: The work represented by this transaction branch took too long.
        </doc>
      </result>
    </command>

    <!-- - Command: dtx.commit   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="commit" code="0x4" label="Commit work on dtx branch">
      <doc>
        Commit the work done on behalf a transaction branch. This command commits the work
        associated with xid. Any produced messages are made available and any consumed messages are
        discarded.
      </doc>

      <exception name="illegal-state" error-code="illegal-state">
        <doc>
          If the command is invoked in an improper context (see class grammar) then the server MUST
          raise an exception.
        </doc>
      </exception>

      <implement role="server" handle="MAY" />

      <field name="xid" type="xid" label="Transaction xid" required="true">
        <doc>
          Specifies the xid of the transaction branch to be committed.
        </doc>

        <exception name="unknown-xid" error-code="not-found">
          <doc>
            If xid is unknown (the transaction branch has not been started or has already been
            ended) then the server MUST raise an exception.
          </doc>
        </exception>

        <exception name="not-disassociated" error-code="illegal-state">
          <doc>
            If this command is called when xid is still associated with a session then the server
            MUST raise an exception.
          </doc>
        </exception>
      </field>

      <field name="one-phase" type="bit" label="One-phase optimization flag">
        <doc>
          Used to indicate whether one-phase or two-phase commit is used.
        </doc>

        <exception name="one-phase" error-code="illegal-state">
          <doc>
            The one-phase bit MUST be set if a commit is sent without a preceding prepare.
          </doc>
        </exception>

        <exception name="two-phase" error-code="illegal-state">
          <doc>
            The one-phase bit MUST NOT be set if the commit has been preceded by prepare.
          </doc>
        </exception>
      </field>

      <result type="xa-result">
        <doc>
          This confirms to the client that the transaction branch is committed or specify the
          error condition.

          The value of this field may be one of the following constants:

          xa-ok: Normal execution

          xa-heurhaz: Due to some failure, the work done on behalf of the specified transaction
              branch may have been heuristically completed.

          xa-heurcom: Due to a heuristic decision, the work done on behalf of the specified
              transaction branch was committed.

          xa-heurrb: Due to a heuristic decision, the work done on behalf of the specified
              transaction branch was rolled back.

          xa-heurmix: Due to a heuristic decision, the work done on behalf of the specified
            transaction branch was partially committed and partially rolled back.

          xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
              reason.

          xa-rbtimeout: The work represented by this transaction branch took too long.
        </doc>
      </result>
    </command>

    <!-- - Command: dtx.forget   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="forget" code="0x5" label="Discard dtx branch">
      <doc>
        This command is called to forget about a heuristically completed transaction branch.
      </doc>

      <exception name="illegal-state" error-code="illegal-state">
        <doc>
          If the command is invoked in an improper context (see class grammar) then the server MUST
          raise an exception.
        </doc>
      </exception>

      <implement role="server" handle="MAY" />

      <field name="xid" type="xid" label="Transaction xid" required="true">
        <doc>
          Specifies the xid of the transaction branch to be forgotten.
        </doc>

        <exception name="unknown-xid" error-code="not-found">
          <doc>
            If xid is unknown (the transaction branch has not been started or has already been
            ended) then the server MUST raise an exception.
          </doc>
        </exception>

        <exception name="not-disassociated" error-code="illegal-state">
          <doc>
            If this command is called when xid is still associated with a session then the server
            MUST raise an exception.
          </doc>
        </exception>
      </field>
    </command>

    <!-- - Command: dtx.get-timeout  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="get-timeout" code="0x6" label="Obtain dtx timeout in seconds">
      <doc>
        This command obtains the current transaction timeout value in seconds. If set-timeout was
        not used prior to invoking this command, the return value is the default timeout; otherwise,
        the value used in the previous set-timeout call is returned.
      </doc>

      <implement role="server" handle="MAY" />

      <field name="xid" type="xid" label="Transaction xid" required="true">
        <doc>
          Specifies the xid of the transaction branch for getting the timeout.
        </doc>

        <exception name="unknown-xid" error-code="not-found">
          <doc>
            If xid is unknown (the transaction branch has not been started or has already been
            ended) then the server MUST raise an exception.
          </doc>
        </exception>
      </field>

      <result>
        <struct name="get-timeout-result" size="4" code="0x2" pack="2">
          <doc> Returns the value of the timeout last specified through set-timeout. </doc>

          <field name="timeout" type="uint32" label="The current transaction timeout value"
            required="true">
            <doc> The current transaction timeout value in seconds. </doc>
          </field>
        </struct>
      </result>
    </command>

    <!-- - Command: dtx.prepare  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="prepare" code="0x7" label="Prepare a dtx branch">
      <doc>
        This command prepares for commitment any message produced or consumed on behalf of xid.
      </doc>

      <exception name="illegal-state" error-code="illegal-state">
        <doc>
          If the command is invoked in an improper context (see class grammar) then the server MUST
          raise an exception.
        </doc>
      </exception>

      <rule name="obligation-1">
        <doc>
          Once this command successfully returns it is guaranteed that the transaction branch may be
          either committed or rolled back regardless of failures.
        </doc>
      </rule>

      <rule name="obligation-2">
        <doc>
          The knowledge of xid cannot be erased before commit or rollback complete the branch.
        </doc>
      </rule>

      <implement role="server" handle="MAY" />

      <field name="xid" type="xid" label="Transaction xid" required="true">
        <doc>
          Specifies the xid of the transaction branch that can be prepared.
        </doc>

        <exception name="unknown-xid" error-code="not-found">
          <doc>
            If xid is unknown (the transaction branch has not been started or has already been
            ended) then the server MUST raise an exception.
          </doc>
        </exception>

        <exception name="not-disassociated" error-code="illegal-state">
          <doc>
            If this command is called when xid is still associated with a session then the server
            MUST raise an exception.
          </doc>
        </exception>
      </field>

      <result type="xa-result">
        <doc>
          This command confirms to the client that the transaction branch is prepared or specify the
          error condition.

          The value of this field may be one of the following constants:

          xa-ok: Normal execution.

          xa-rdonly: The transaction branch was read-only and has been committed.

          xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
              reason.

          xa-rbtimeout: The work represented by this transaction branch took too long.
        </doc>
      </result>
    </command>

    <!-- - Command: dtx.recover  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="recover" code="0x8" label="Get prepared or completed xids">
      <doc>
        This command is called to obtain a list of transaction branches that are in a prepared or
        heuristically completed state.
      </doc>

      <implement role="server" handle="MAY" />

      <result>
        <struct name="recover-result" size="4" code="0x3" pack="2">
          <doc>
            Returns to the client a table with single item that is a sequence of transaction xids
            that are in a prepared or heuristically completed state.
          </doc>

          <field name="in-doubt" type="array" label="array of xids to be recovered" required="true">
            <doc> Array containing the xids to be recovered (xids that are in a prepared or
              heuristically completed state). </doc>

          </field>
        </struct>
      </result>
    </command>

    <!-- - Command: dtx.rollback   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="rollback" code="0x9" label="Rollback a dtx branch">
      <doc>
        This command rolls back the work associated with xid. Any produced messages are discarded
        and any consumed messages are re-enqueued.
      </doc>

      <exception name="illegal-state" error-code="illegal-state">
        <doc>
          If the command is invoked in an improper context (see class grammar) then the server MUST
          raise an exception.
        </doc>
      </exception>

      <implement role="server" handle="MAY" />

      <field name="xid" type="xid" label="Transaction xid" required="true">
        <doc>
          Specifies the xid of the transaction branch that can be rolled back.
        </doc>

        <exception name="unknown-xid" error-code="not-found">
          <doc>
            If xid is unknown (the transaction branch has not been started or has already been
            ended) then the server MUST raise an exception.
          </doc>
        </exception>

        <exception name="not-disassociated" error-code="illegal-state">
          <doc>
            If this command is called when xid is still associated with a session then the server
            MUST raise an exception.
          </doc>
        </exception>
      </field>

      <result type="xa-result">
        <doc>
          This command confirms to the client that the transaction branch is rolled back or specify
          the error condition.

          The value of this field may be one of the following constants:

          xa-ok: Normal execution

          xa-heurhaz: Due to some failure, the work done on behalf of the specified transaction
              branch may have been heuristically completed.

          xa-heurcom: Due to a heuristic decision, the work done on behalf of the specified
              transaction branch was committed.

          xa-heurrb: Due to a heuristic decision, the work done on behalf of the specified
              transaction branch was rolled back.

          xa-heurmix: Due to a heuristic decision, the work done on behalf of the specified
              transaction branch was partially committed and partially rolled back.

          xa-rbrollback: The broker marked the transaction branch rollback-only for an unspecified
              reason.

          xa-rbtimeout: The work represented by this transaction branch took too long.
        </doc>
      </result>
    </command>

    <!-- - Command: dtx.set-timeout  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="set-timeout" code="0xa" label="Set dtx timeout value">
      <doc>
        Sets the specified transaction branch timeout value in seconds.
      </doc>

      <rule name="effective">
        <doc>
          Once set, this timeout value is effective until this command is reinvoked with a different
          value.
        </doc>
      </rule>

      <rule name="reset">
        <doc>
          A value of zero resets the timeout value to the default value.
        </doc>
      </rule>

      <implement role="server" handle="MAY" />

      <field name="xid" type="xid" label="Transaction xid" required="true">
        <doc>
          Specifies the xid of the transaction branch for setting the timeout.
        </doc>

        <exception name="unknown-xid" error-code="not-found">
          <doc>
            If xid is unknown (the transaction branch has not been started or has already been
            ended) then the server MUST raise an exception.
          </doc>
        </exception>

      </field>

      <field name="timeout" type="uint32" label="Dtx timeout in seconds" required="true">
        <doc>
          The transaction timeout value in seconds.
        </doc>
      </field>
    </command>

  </class>

  <!-- == Class: exchange ====================================================================== -->

  <class name="exchange" code="0x7" label="work with exchanges">
    <doc>
      Exchanges match and distribute messages across queues. Exchanges can be configured in the
      server or created at runtime.
    </doc>

    <doc type="grammar">
      exchange  = C:DECLARE
                / C:DELETE
                / C:QUERY
    </doc>

    <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.

        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 commands (such as message.transfer).
      </doc>
      <doc type="scenario">
        Client creates 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 commands (such as message.transfer) and for default queue
        bindings.
      </doc>
      <doc type="scenario">
        Client checks that the default exchange is active by 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 default exchange MUST NOT be accessible to the client except by specifying an empty
        exchange name in a content publish command (such as message.transfer). That is, the server
        must not let clients explicitly bind, unbind, delete, or make any other reference to this
        exchange.
      </doc>
    </rule>

    <rule name="extensions">
      <doc>
        The server MAY implement other exchange types as wanted.
      </doc>
    </rule>

    <role name="server" implement="MUST" />
    <role name="client" implement="MUST" />

    <domain name="name" type="str8" label="exchange name">
      <doc>
        The exchange name is a client-selected string that identifies the exchange for publish
        commands. Exchange names may consist of any mixture of digits, letters, and underscores.
        Exchange names are scoped by the virtual host.
      </doc>
    </domain>

    <!-- - Command: exchange.declare - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="declare" code="0x1" label="verify exchange exists, create if needed">
      <doc>
        This command 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 creates as many exchanges as it can until the server reports an error; the
          number of exchanges successfully created must be at least sixteen.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />

      <field name="exchange" type="name" required="true">
        <exception name="reserved-names" error-code="not-allowed">
          <doc>
            Exchange names starting with "amq." are reserved for pre-declared and standardized
            exchanges. The client MUST NOT attempt to create an exchange starting with "amq.".
          </doc>
        </exception>

        <exception name="exchange-name-required" error-code="invalid-argument">
          <doc>
            The name of the exchange MUST NOT be a blank or empty string.
          </doc>
        </exception>
      </field>

      <field name="type" type="str8" label="exchange type" required="true">
        <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>

        <exception name="typed" error-code="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 command.
          </doc>
        </exception>

        <exception name="exchange-type-not-found" error-code="not-found">
          <doc>
            If the client attempts to create an exchange which the server does not recognize, an
            exception MUST be sent.
          </doc>
        </exception>
      </field>

      <field name="alternate-exchange" type="name" label= "exchange name for unroutable messages">
        <doc>
          In the event that a message cannot be routed, this is the name of the exchange to which
          the message will be sent. Messages transferred using message.transfer will be routed to
          the alternate-exchange only if they are sent with the "none" accept-mode, and the
          discard-unroutable delivery property is set to false, and there is no queue to route to
          for the given message according to the bindings on this exchange.
        </doc>

        <rule name="empty-name">
          <doc>
            If alternate-exchange is not set (its name is an empty string), unroutable messages
            that would be sent to the alternate-exchange MUST be dropped silently.
          </doc>
        </rule>

        <exception name="pre-existing-exchange" error-code="not-allowed">
          <doc>
            If the alternate-exchange is not empty and if the exchange already exists with a
            different alternate-exchange, then the declaration MUST result in an exception.
          </doc>
        </exception>

        <rule name="double-failure">
          <doc>
            A message which is being routed to a alternate exchange, MUST NOT be re-routed to a
            secondary alternate exchange if it fails to route in the primary alternate exchange.
            After such a failure, the message MUST be dropped. This prevents looping.
          </doc>
        </rule>
      </field>

      <field name="passive" type="bit" label="do not create exchange">
        <doc>
          If set, the server will not create the exchange. The client can use this to check whether
          an exchange exists without modifying the server state.
        </doc>
        <exception name="not-found" error-code="not-found">
          <doc>
            If set, and the exchange does not already exist, the server MUST raise an exception.
          </doc>
        </exception>
      </field>

      <field name="durable" type="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>
        </rule>

        <rule name="sticky">
          <doc>
            The server MUST ignore the durable field if the exchange already exists.
          </doc>
        </rule>
      </field>

      <field name="auto-delete" type="bit" label="auto-delete when unused">
        <doc>
          If set, the exchange is deleted automatically when there remain no bindings between the
          exchange and any queue. Such an exchange will not be automatically deleted until at least
          one binding has been made to prevent the immediate deletion of the exchange upon creation.
        </doc>
        <rule name="sticky">
          <doc>
            The server MUST ignore the auto-delete field if the exchange already exists.
          </doc>
        </rule>
      </field>

      <field name="arguments" type="map" label="arguments for declaration">
        <doc>
          A set of arguments for the declaration. The syntax and semantics of these arguments
          depends on the server implementation. This field is ignored if passive is 1.
        </doc>

        <exception name="unknown-argument" error-code="not-implemented">
          <doc>
            If the arguments field contains arguments which are not understood by the server,
            it MUST raise an exception.
          </doc>
        </exception>
      </field>
    </command>

    <!-- - Command: exchange.delete  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="delete" code="0x2" label="delete an exchange">
      <doc>
        This command deletes an exchange. When an exchange is deleted all queue bindings on the
        exchange are cancelled.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="exchange" type="name" required="true">
        <exception name="exists" error-code="not-found">
          <doc>
            The client MUST NOT attempt to delete an exchange that does not exist.
          </doc>
        </exception>

        <exception name="exchange-name-required" error-code="invalid-argument">
          <doc>
            The name of the exchange MUST NOT be a missing or empty string.
          </doc>
        </exception>

        <exception name="used-as-alternate" error-code="not-allowed">
          <doc>
            An exchange MUST NOT be deleted if it is in use as an alternate-exchange by a queue or
            by another exchange.
          </doc>
        </exception>

      </field>

      <field name="if-unused" type="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 an exception
          instead.
        </doc>
        <exception name="exchange-in-use" error-code="precondition-failed">
          <doc>
            If the exchange has queue bindings, and the if-unused flag is set, the server MUST NOT
            delete the exchange, but MUST raise and exception.
          </doc>
        </exception>
      </field>
    </command>

    <!-- - Command: exchange.query - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="query" code="0x3" label="request information about an exchange">
      <doc>
        This command is used to request information on a particular exchange.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="name" type="str8" label="the exchange name">
        <doc>
           The name of the exchange for which information is requested. If not specified explicitly
           the default exchange is implied.
        </doc>
      </field>

      <result>
        <struct name="exchange-query-result" size="4" code="0x1" pack="2">
          <doc>
            This is sent in response to a query request and conveys information on a particular
            exchange.
          </doc>

          <field name="type" type="str8" label="indicate the exchange type">
            <doc>
               The type of the exchange. Will be empty if the exchange is not found.
            </doc>
          </field>

          <field name="durable" type="bit" label="indicate the durability">
            <doc>
              The durability of the exchange, i.e. if set the exchange is durable. Will not be set
              if the exchange is not found.
            </doc>
          </field>

          <field name="not-found" type="bit" label="indicate an unknown exchange">
            <doc>
               If set, the exchange for which information was requested is not known.
            </doc>
          </field>

          <field name="arguments" type="map" label="other unspecified exchange properties">
            <doc>
              A set of properties of the exchange whose syntax and semantics depends on the server
              implementation. Will be empty if the exchange is not found.
            </doc>
          </field>
        </struct>
      </result>
    </command>

    <!-- - Command: exchange.bind  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="bind" code="0x4" label="bind queue to an exchange">
      <doc> This command 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 ignore duplicate bindings - that is, two or more bind commands with the
          same exchange, queue, and binding-key - without treating these as an error.  The value of
          the arguments used for the binding MUST NOT be altered by subsequent binding requests.
        </doc>
        <doc type="scenario">
          A client binds a named queue to an exchange. The client then repeats the bind (with
          identical exchange, queue, and binding-key).  The second binding should use a different
          value for the arguments field.
        </doc>
      </rule>

      <rule name="durable-exchange">
        <doc> Bindings between durable queues and durable exchanges are automatically durable and
          the server MUST restore such bindings after a server restart. </doc>
        <doc type="scenario"> A server creates 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 creates a named queue and attempts to bind it to 4 different
          exchanges. </doc>
      </rule>

      <rule name="multiple-bindings">
        <doc> Where more than one binding exists between a particular exchange instance and a
          particular queue instance any given message published to that exchange should be delivered
          to that queue at most once, regardless of how many distinct bindings match. </doc>
        <doc type="scenario"> A client creates a named queue and binds it to the same topic exchange
          at least three times using intersecting binding-keys (for example, "animals.*",
          "animals.dogs.*", "animal.dogs.chihuahua"). Verify that a message matching all the
          bindings (using previous example, routing key = "animal.dogs.chihuahua") is delivered once
          only. </doc>
      </rule>

      <implement role="server" handle="MUST"/>

      <field name="queue" type="queue.name" required="true">
        <doc> Specifies the name of the queue to bind. </doc>

        <exception name="empty-queue" error-code="invalid-argument">
          <doc> A client MUST NOT be allowed to bind a non-existent and unnamed queue (i.e. empty
            queue name) to an exchange. </doc>
          <doc type="scenario"> A client attempts to bind with an unnamed (empty) queue name to an
            exchange. </doc>
        </exception>

        <exception name="queue-existence" error-code="not-found">
          <doc> A client MUST NOT be allowed to bind a non-existent queue (i.e. not previously
            declared) to an exchange. </doc>
          <doc type="scenario"> A client attempts to bind an undeclared queue name to an exchange.
          </doc>
        </exception>
      </field>

      <field name="exchange" type="name" label="name of the exchange to bind to" required="true">
        <exception name="exchange-existence" error-code="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 a named queue to a undeclared exchange.
          </doc>
        </exception>

        <exception name="exchange-name-required" error-code="invalid-argument">
          <doc> The name of the exchange MUST NOT be a blank or empty string. </doc>
        </exception>
      </field>

      <field name="binding-key" type="str8"
        label="identifies a binding between a given exchange and queue" required="true">
        <doc> The binding-key uniquely identifies a binding between a given (exchange, queue) pair.
          Depending on the exchange configuration, the binding key may be matched against the
          message routing key in order to make routing decisions. The match algorithm depends on the
          exchange type. Some exchange types may ignore the binding key when making routing
          decisions. Refer to the specific exchange type documentation. The meaning of an empty
          binding key depends on the exchange implementation. </doc>
      </field>

      <field name="arguments" type="map" 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>

        <exception name="unknown-argument" error-code="not-implemented">
          <doc> If the arguments field contains arguments which are not understood by the server, it
            MUST raise an exception. </doc>
        </exception>
      </field>
    </command>

    <!-- - Command: exchange.unbind  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="unbind" code="0x5" label="unbind a queue from an exchange">
      <doc>
        This command unbinds a queue from an exchange.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="queue" type="queue.name" required="true">
        <doc>
          Specifies the name of the queue to unbind.
        </doc>
        <exception name="non-existent-queue" error-code="not-found">
          <doc>
            If the queue does not exist the server MUST raise an exception.
          </doc>
        </exception>
      </field>

      <field name="exchange" type="name" required="true">
        <doc>
          The name of the exchange to unbind from.
        </doc>

        <exception name="non-existent-exchange" error-code="not-found">
          <doc>
            If the exchange does not exist the server MUST raise an exception.
          </doc>
        </exception>

        <exception name="exchange-name-required" error-code="invalid-argument">
          <doc>
            The name of the exchange MUST NOT be a blank or empty string.
          </doc>
        </exception>
      </field>

      <field name="binding-key" type="str8" label="the key of the binding" required="true">
        <doc>
          Specifies the binding-key of the binding to unbind.
        </doc>

        <exception name="non-existent-binding-key" error-code="not-found">
          <doc>
            If there is no matching binding-key the server MUST raise an exception.
          </doc>
        </exception>
      </field>
    </command>

    <!-- - Command: exchange.bound - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="bound" code="0x6" label="request information about bindings to an exchange">
      <doc>
        This command is used to request information on the bindings to a particular exchange.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="exchange" type="str8" label="the exchange name">
        <doc>
           The name of the exchange for which binding information is being requested. If not
           specified explicitly the default exchange is implied.
        </doc>
      </field>

      <field name="queue" type="str8" label="a queue name" required="true">
        <doc>
          If populated then determine whether the given queue is bound to the exchange.
        </doc>
      </field>

      <field name="binding-key" type="str8" label="a binding-key">
        <doc>
          If populated defines the binding-key of the binding of interest, if not populated the
          request will ignore the binding-key on bindings when searching for a match.
        </doc>
      </field>

      <field name="arguments" type="map" label="a set of binding arguments">
        <doc>
          If populated defines the arguments of the binding of interest if not populated the request
          will ignore the arguments on bindings when searching for a match
        </doc>
      </field>

      <result>
        <struct name="exchange-bound-result" size="4" code="0x2" pack="2">
          <field name="exchange-not-found" type="bit" label="indicate an unknown exchange">
            <doc>
               If set, the exchange for which information was requested is not known.
            </doc>
          </field>

          <field name="queue-not-found" type="bit" label="indicate an unknown queue">
            <doc>
               If set, the queue specified is not known.
            </doc>
          </field>

          <field name="queue-not-matched" type="bit" label="indicate no matching queue">
            <doc>
              A bit which if set indicates that no binding was found from the specified exchange to
              the specified queue.
            </doc>
          </field>

          <field name="key-not-matched" type="bit" label="indicate no matching binding-key">
            <doc>
              A bit which if set indicates that no binding was found from the specified exchange
              with the specified binding-key.
            </doc>
          </field>

          <field name="args-not-matched" type="bit" label="indicate no matching arguments">
            <doc>
              A bit which if set indicates that no binding was found from the specified exchange
              with the specified arguments.
            </doc>
          </field>
        </struct>
      </result>
    </command>

  </class>

  <!-- == Class: queue ========================================================================= -->

  <class name="queue" code="0x8" 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
            / C:BIND
            / C:PURGE
            / C:DELETE
            / C:QUERY
            / C:UNBIND
    </doc>

    <rule name="any-content">
      <doc>
        A server MUST allow any content class to be sent to any queue, in any mix, and queue and
        deliver these content classes independently. Note that all commands that fetch content off
        queues are specific to a given content class.
      </doc>
      <doc type="scenario">
        Client creates an exchange of each standard type and several queues that it binds to each
        exchange. It must then successfully send each of the standard content types to each of the
        available queues.
      </doc>
    </rule>

    <role name="server" implement="MUST" />
    <role name="client" implement="MUST" />

    <domain name="name" type="str8" label="queue name">
      <doc>
        The queue name identifies the queue within the virtual host. Queue names must have a length
        of between 1 and 255 characters inclusive, must start with a digit, letter or underscores
        ('_') character, and must be otherwise encoded in UTF-8.
      </doc>
    </domain>

    <!-- - Command: queue.declare  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="declare" code="0x1" label="declare queue">
      <doc>
        This command 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-created queue to the default
          exchange, which is an exchange of type 'direct' and use the queue name as the binding-key.
        </doc>
        <doc type="scenario">
          Client creates 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 binding-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 create as many queues as it can until the server reports an error. The
          resulting count must at least be 256.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />

      <field name="queue" type="name" required="true">
        <exception name="reserved-prefix" error-code="not-allowed">
          <doc>
            Queue names starting with "amq." are reserved for pre-declared and standardized server
            queues. A client MUST NOT attempt to declare a queue with a name that starts with "amq."
            and the passive option set to zero.
          </doc>
          <doc type="scenario">
            A client attempts to create a queue with a name starting with "amq." and with the
            passive option set to zero.
          </doc>
        </exception>
      </field>

      <field name="alternate-exchange" type="exchange.name"
        label= "exchange name for messages with exceptions">
        <doc>
          The alternate-exchange field specifies how messages on this queue should be treated when
          they are rejected by a subscriber, or when they are orphaned by queue deletion. When
          present, rejected or orphaned messages MUST be routed to the alternate-exchange. In all
          cases the messages MUST be removed from the queue.
        </doc>

        <exception name="pre-existing-exchange" error-code="not-allowed">
          <doc>
            If the alternate-exchange is not empty and if the queue already exists with a different
            alternate-exchange, then the declaration MUST result in an exception.
          </doc>
        </exception>

        <exception name="unknown-exchange" error-code="not-found">
          <doc>
            if the alternate-exchange does not match the name of any existing exchange on the
            server, then an exception must be raised.
          </doc>
        </exception>
      </field>

      <field name="passive" type="bit" label="do not create queue">
        <doc>
          If set, the server will not create the queue. This field allows the client to assert the
          presence of a queue without modifying the server state.
        </doc>

        <exception name="passive" error-code="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 command to
            succeed. Client then attempts to declare a non-existent queue with the passive option,
            and the server must close the session with the correct exception.
          </doc>
        </exception>
      </field>

      <field name="durable" type="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 queue definition MUST survive the server losing all transient memory, e.g. a
            machine restart.
          </doc>
          <doc type="scenario">
            Client creates a durable queue; server is then restarted. Client then attempts to send
            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 creates two named queues, one durable and one transient.
          </doc>
        </rule>

        <rule name="pre-existence">
          <doc>
            The server MUST ignore the durable field if the queue already exists.
          </doc>
          <doc type="scenario">
            A client creates two named queues, one durable and one transient. The client then
            attempts to declare the two queues using the same names again, but reversing the value
            of the durable flag in each case. Verify that the queues still exist with the original
            durable flag values.
          </doc>
        </rule>
      </field>

      <field name="exclusive" type="bit" label="request an exclusive queue">
        <doc>
          Exclusive queues can only be used from one session at a time. Once a session
          declares an exclusive queue, that queue cannot be used by any other session until the
          declaring session closes.
        </doc>

        <rule name="types">
          <doc>
            The server MUST support both exclusive (private) and non-exclusive (shared) queues.
          </doc>
          <doc type="scenario">
            A client creates two named queues, one exclusive and one non-exclusive.
          </doc>
        </rule>

        <exception name="in-use" error-code="resource-locked">
          <doc>
            If the server receives a declare, bind, consume or get request for a queue that has been
            declared as exclusive by an existing client session, it MUST raise an exception.
          </doc>
          <doc type="scenario">
            A client declares an exclusive named queue. A second client on a different session
            attempts to declare a queue of the same name.
          </doc>
        </exception>
      </field>

      <field name="auto-delete" type="bit" label="auto-delete queue when unused">
        <doc>
            If this field is set and the exclusive field is also set, then the queue MUST be deleted
            when the session closes.

            If this field is set and the exclusive field is not set the queue is deleted when all
            the consumers have finished using it. Last consumer can be cancelled either explicitly
            or because its session is closed. If there was no consumer ever on the queue, it won't
            be deleted.
        </doc>

        <rule name="pre-existence">
          <doc>
            The server MUST ignore the auto-delete field if the queue already exists.
          </doc>
          <doc type="scenario">
            A client creates two named queues, one as auto-delete and one explicit-delete. The
            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="arguments" type="map" label="arguments for declaration">
        <doc>
          A set of arguments for the declaration. The syntax and semantics of these arguments
          depends on the server implementation. This field is ignored if passive is 1.
        </doc>

        <exception name="unknown-argument" error-code="not-implemented">
          <doc>
            If the arguments field contains arguments which are not understood by the server,
            it MUST raise an exception.
          </doc>
        </exception>
      </field>
    </command>

    <!-- - Command: queue.delete - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="delete" code="0x2" label="delete a queue">
      <doc>
        This command deletes a queue. When a queue is deleted any pending messages are sent to the
        alternate-exchange if defined, or discarded if it is not.
      </doc>


      <implement role="server" handle="MUST" />

      <field name="queue" type="name" required="true">
        <doc>
          Specifies the name of the queue to delete.
        </doc>

        <exception name="empty-name" error-code="invalid-argument">
          <doc>
            If the queue name in this command is empty, the server MUST raise an exception.
          </doc>
        </exception>

        <exception name="queue-exists" error-code="not-found">
          <doc>
            The queue must exist. If the client attempts to delete a non-existing queue the server
            MUST raise an exception.
          </doc>
        </exception>
      </field>

      <field name="if-unused" type="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 an exception instead.
        </doc>

        <exception name="if-unused-flag" error-code="precondition-failed">
          <doc>
            The server MUST respect the if-unused flag when deleting a queue.
          </doc>
        </exception>
      </field>

      <field name="if-empty" type="bit" label="delete only if empty">
        <doc>
          If set, the server will only delete the queue if it has no messages.
        </doc>
        <exception name="not-empty" error-code="precondition-failed">
          <doc>
            If the queue is not empty the server MUST raise an exception.
          </doc>
        </exception>
      </field>
    </command>

    <!-- - Command: queue.purge  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="purge" code="0x3" label="purge a queue">
      <doc>
        This command removes all messages from a queue. It does not cancel subscribers. Purged
        messages are deleted without any formal "undo" mechanism.
      </doc>

      <rule name="empty">
        <doc>
          A call to purge MUST result in an empty queue.
        </doc>
      </rule>

      <rule name="pending-messages">
        <doc>
          The server MUST NOT purge messages that have already been sent to a client but not yet
          accepted.
        </doc>
      </rule>

      <rule name="purge-recovery">
        <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>

      <implement role="server" handle="MUST" />

      <field name="queue" type="name" required="true">
        <doc>
          Specifies the name of the queue to purge.
        </doc>

        <exception name="empty-name" error-code="invalid-argument">
          <doc>
            If the the queue name in this command is empty, the server MUST raise an exception.
          </doc>
        </exception>

        <exception name="queue-exists" error-code="not-found">
          <doc>
            The queue MUST exist. Attempting to purge a non-existing queue MUST cause an exception.
          </doc>
        </exception>
      </field>
    </command>

    <!-- - Command: queue.query  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="query" code="0x4" label="request information about a queue">
      <doc>
        This command requests information about a queue.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="queue" type="name" label="the queried queue" required="true"/>

      <result>
        <struct name="queue-query-result" size="4" code="0x1" pack="2">
          <doc>
            This is sent in response to queue.query, and conveys the requested information about a
            queue.  If no queue with the specified name exists then none of the fields within the
            returned result struct will be populated.
          </doc>

          <field name="queue" type="name" required="true">
            <doc>
              Reports the name of the queue.
            </doc>
          </field>

          <field name="alternate-exchange" type="exchange.name" />

          <field name="durable" type="bit" />

          <field name="exclusive" type="bit" />

          <field name="auto-delete" type="bit" />

          <field name="arguments" type="map" />

          <field name="message-count" type="uint32" label="number of messages in queue"
            required="true">
            <doc> Reports the number of messages in the queue. </doc>
          </field>

          <field name="subscriber-count" type="uint32" label="number of subscribers"
                 required="true">
            <doc>
              Reports the number of subscribers for the queue.
            </doc>
          </field>
        </struct>
      </result>
    </command>

  </class>

  <!-- == Class: file ========================================================================== -->

  <class name="file" code="0x9" label="work with file content">
    <doc>
      The file class provides commands that support reliable file transfer. File messages have a
      specific set of properties that are required for interoperability with file transfer
      applications. File messages and acknowledgements are subject to session transactions. Note
      that the file class does not provide message browsing commands; these are not compatible with
      the staging model. Applications that need browsable file transfer should use Message content
      and the Message class.
    </doc>

    <doc type="grammar">
      file  = C:QOS S:QOS-OK
            / C:CONSUME S:CONSUME-OK
            / C:CANCEL
            / C:OPEN S:OPEN-OK C:STAGE content
            / S:OPEN C:OPEN-OK S:STAGE content
            / C:PUBLISH
            / S:DELIVER
            / S:RETURN
            / C:ACK
            / C:REJECT
    </doc>

    <rule name="reliable-storage">
      <doc>
        The server MUST make a best-effort to hold file messages on a reliable storage mechanism.
      </doc>
    </rule>

    <rule name="no-discard">
      <doc>
        The server MUST NOT discard a file message in case of a queue overflow. The server MUST use
        the Session.Flow command to slow or stop a file message publisher when necessary.
      </doc>
    </rule>

    <rule name="priority-levels">
      <doc>
        The server MUST implement at least 2 priority levels for file messages, where priorities 0-4
        and 5-9 are treated as two distinct levels. The server MAY implement up to 10 priority
        levels.
      </doc>
    </rule>

    <rule name="acknowledgement-support">
      <doc>
        The server MUST support both automatic and explicit acknowledgements on file content.
      </doc>
    </rule>

    <role name="server" implement="MAY" />
    <role name="client" implement="MAY" />

    <!--  These are the properties for a File content  -->
    <struct name="file-properties" size="4" code="0x1" pack="2">
      <field name="content-type" type="str8" label="MIME content type" />
      <field name="content-encoding" type="str8" label="MIME content encoding" />
      <field name="headers" type="map" label="message header field table" />
      <field name="priority" type="uint8" label="message priority, 0 to 9" />
      <field name="reply-to" type="str8" label="destination to reply to" />
      <field name="message-id" type="str8" label="application message identifier" />
      <field name="filename" type="str8" label="message filename" />
      <field name="timestamp" type="datetime" label="message timestamp" />
      <!-- This field is deprecated pending review -->
      <field name="cluster-id" type="str8" label="intra-cluster routing identifier" />
    </struct>

    <domain name="return-code" type="uint16" label="return code from server">
      <doc>
        The return code. The AMQP return codes are defined by this enum.
      </doc>
      <enum>
        <choice name="content-too-large" value="311">
          <doc>
            The client attempted to transfer content larger than the server could accept.
          </doc>
        </choice>

        <choice name="no-route" value="312">
          <doc>
            The exchange cannot route a message, most likely due to an invalid routing key. Only
            when the mandatory flag is set.
          </doc>
        </choice>

        <choice name="no-consumers" value="313">
          <doc>
            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>
        </choice>
      </enum>
    </domain>

    <!-- - Command: file.qos - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="qos" code="0x1" label="specify quality of service">
      <doc>
        This command requests a specific quality of service. The QoS can be specified for the
        current session or for all sessions on the connection. The particular properties and
        semantics of a qos command always depend on the content class semantics. Though the qos
        command could in principle apply to both peers, it is currently meaningful only for the
        server.
      </doc>

      <implement role="server" handle="MUST" />

      <response name="qos-ok" />

      <field name="prefetch-size" type="uint32" label="pre-fetch 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 within the session. Pre-fetching gives a performance improvement. This field
          specifies the pre-fetch window size in octets. May be set to zero, meaning "no specific
          limit". Note that other pre-fetch limits may still apply. The prefetch-size is ignored if
          the no-ack option is set.
        </doc>
      </field>

      <field name="prefetch-count" type="uint16" label="pre-fetch window in messages">
        <doc>
          Specifies a pre-fetch window in terms of whole messages. This is compatible with some file
          API implementations. This field may be used in combination with the prefetch-size field; a
          message will only be sent in advance if both pre-fetch windows (and those at the session
          and connection level) allow it. The prefetch-count is ignored if the no-ack option is set.
        </doc>

        <rule name="prefetch-discretion">
          <doc>
            The server MAY send less data in advance than allowed by the client's specified
            pre-fetch windows but it MUST NOT send more.
          </doc>
        </rule>
      </field>

      <field name="global" type="bit" label="apply to entire connection">
        <doc>
          By default the QoS settings apply to the current session only. If this field is set, they
          are applied to the entire connection.
        </doc>
      </field>
    </command>

    <!-- - Command: file.qos-ok  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="qos-ok" code="0x2" label="confirm the requested qos">
      <doc>
        This command 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>

      <implement role="client" handle="MUST" />
    </command>

    <!-- - Command: file.consume - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="consume" code="0x3" label="start a queue consumer">
      <doc>
        This command asks the server to start a "consumer", which is a transient request for
        messages from a specific queue. Consumers last as long as the session they were created on,
        or until the client cancels them.
      </doc>

      <rule name="min-consumers">
        <doc>
          The server SHOULD support at least 16 consumers per queue, unless the queue was declared
          as private, and ideally, impose no limit except as defined by available resources.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />

      <response name="consume-ok" />

      <field name="queue" type="queue.name">
        <doc>
          Specifies the name of the queue to consume from.
        </doc>

        <exception name="queue-exists-if-empty" error-code="not-allowed">
          <doc>
            If the queue name in this command is empty, the server MUST raise an exception.
          </doc>
        </exception>
      </field>

      <field name="consumer-tag" type="str8">
        <doc>
          Specifies the identifier for the consumer. The consumer tag is local to a connection, so
          two clients can use the same consumer tags.
        </doc>

        <exception name="not-existing-consumer" error-code="not-allowed">
          <doc>
            The tag MUST NOT refer to an existing consumer. If the client attempts to create two
            consumers with the same non-empty tag the server MUST raise an exception.
          </doc>
        </exception>

        <exception name="not-empty-consumer-tag" error-code="not-allowed">
          <doc>
            The client MUST NOT specify a tag that is empty or blank.
          </doc>
          <doc type="scenario">
            Attempt to create a consumers with an empty tag.
          </doc>
        </exception>
      </field>

      <field name="no-local" type="bit">
        <doc>If the no-local field is set the server will not send messages to the connection that
          published them.</doc>
      </field>

      <field 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 automatically and silently
          acknowledges it on behalf of the client. This functionality increases performance but at
          the cost of reliability. Messages can get lost if a client dies before it can deliver them
          to the application.
        </doc>
      </field>

      <field name="exclusive" type="bit" label="request exclusive access">
        <doc>
          Request exclusive consumer access, meaning only this consumer can access the queue.
        </doc>

        <exception name="in-use" error-code="resource-locked">
          <doc>
            If the server cannot grant exclusive access to the queue when asked, - because there are
            other consumers active - it MUST raise an exception.
          </doc>
        </exception>
      </field>

      <field name="nowait" type="bit" label="do not send a reply command">
        <doc>
          If set, the server will not respond to the command. The client should not wait for a reply
          command. If the server could not complete the command it will raise an exception.
        </doc>
      </field>

      <field name="arguments" type="map" label="arguments for consuming">
        <doc>
          A set of arguments for the consume. The syntax and semantics of these arguments depends on
          the providers implementation.
        </doc>
      </field>
    </command>

    <command name="consume-ok" code="0x4" label="confirm a new consumer">
      <doc>
        This command provides the client with a consumer tag which it MUST use in commands that work
        with the consumer.
      </doc>

      <implement role="client" handle="MUST" />

      <field name="consumer-tag" type="str8">
        <doc>
          Holds the consumer tag specified by the client or provided by the server.
        </doc>
      </field>
    </command>

    <!-- - Command: file.cancel  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="cancel" code="0x5" label="end a queue consumer">
      <doc>
        This command 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.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="consumer-tag" type="str8">
        <doc>
          the identifier of the consumer to be cancelled.
        </doc>
      </field>
    </command>

    <!-- - Command: file.open  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="open" code="0x6" label="request to start staging">
      <doc>
        This command requests permission to start staging a message. Staging means sending the
        message into a temporary area at the recipient end and then delivering the message by
        referring to this temporary area. Staging is how the protocol handles partial file transfers
        - if a message is partially staged and the connection breaks, the next time the sender
        starts to stage it, it can restart from where it left off.
      </doc>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <response name="open-ok" />

      <field name="identifier" type="str8" label="staging identifier">
        <doc>
          This is the staging identifier. This is an arbitrary string chosen by the sender. For
          staging to work correctly the sender must use the same staging identifier when staging the
          same message a second time after recovery from a failure. A good choice for the staging
          identifier would be the SHA1 hash of the message properties data (including the original
          filename, revised time, etc.).
        </doc>
      </field>

      <field name="content-size" type="uint64" label="message content size">
        <doc>
          The size of the content in octets. The recipient may use this information to allocate or
          check available space in advance, to avoid "disk full" errors during staging of very large
          messages.
        </doc>

        <rule name="content-size">
          <doc>
            The sender MUST accurately fill the content-size field. Zero-length content is
            permitted.
          </doc>
        </rule>
      </field>
    </command>

    <!-- - Command: file.open-ok - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="open-ok" code="0x7" label="confirm staging ready">
      <doc>
        This command confirms that the recipient is ready to accept staged data. If the message was
        already partially-staged at a previous time the recipient will report the number of octets
        already staged.
      </doc>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <response name="stage" />

      <field name="staged-size" type="uint64" label="already staged amount">
        <doc>
          The amount of previously-staged content in octets. For a new message this will be zero.
        </doc>

        <rule name="behavior">
          <doc>
            The sender MUST start sending data from this octet offset in the message, counting from
            zero.
          </doc>
        </rule>

        <rule name="staging">
          <doc>
            The recipient MAY decide how long to hold partially-staged content and MAY implement
            staging by always discarding partially-staged content. However if it uses the file
            content type it MUST support the staging commands.
          </doc>
        </rule>
      </field>
    </command>

    <!-- - Command: file.stage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="stage" code="0x8" label="stage message content">
      <doc>
        This command stages the message, sending the message content to the recipient from the octet
        offset specified in the Open-Ok command.
      </doc>

      <implement role="server" handle="MUST" />
      <implement role="client" handle="MUST" />

      <segments>
        <header required="true">
          <entry type="file-properties"/>
        </header>
        <body/>
      </segments>
    </command>

    <!-- - Command: file.publish - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="publish" code="0x9" label="publish a message">
      <doc>
        This command publishes a staged file message to a specific exchange. The file 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>

      <implement role="server" handle="MUST" />

      <field name="exchange" type="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 an exception.
        </doc>

        <rule name="default">
          <doc>
            The server MUST accept a blank exchange name to mean the default exchange.
          </doc>
        </rule>

        <exception name="refusal" error-code="not-implemented">
          <doc>
            The exchange MAY refuse file content in which case it MUST send an exception.
          </doc>
        </exception>
      </field>

      <field name="routing-key" type="str8" 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" type="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 command. If
          this flag is zero, the server silently drops the message.
        </doc>

        <rule name="implementation">
          <doc>
            The server SHOULD implement the mandatory flag.
          </doc>
        </rule>
      </field>

      <field name="immediate" type="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 command. If this flag is zero, the server will queue the message, but with
          no guarantee that it will ever be consumed.
        </doc>

        <rule name="implementation">
          <doc>
            The server SHOULD implement the immediate flag.
          </doc>
        </rule>
      </field>

      <field name="identifier" type="str8" label="staging identifier">
        <doc>
          This is the staging identifier of the message to publish. The message must have been
          staged. Note that a client can send the Publish command asynchronously without waiting for
          staging to finish.
        </doc>
      </field>
    </command>

    <!-- - Command: file.return  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="return" code="0xa" label="return a failed message">
      <doc>
        This command 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>

      <implement role="client" handle="MUST" />

      <field name="reply-code" type="return-code" />

      <field name="reply-text" type="str8" label="The localized reply text.">
          <doc>
              This text can be logged as an aid to resolving issues.
          </doc>
      </field>

      <field name="exchange" type="exchange.name">
        <doc>
          Specifies the name of the exchange that the message was originally published to.
        </doc>
      </field>

      <field name="routing-key" type="str8" label="Message routing key">
        <doc>
          Specifies the routing key name specified when the message was published.
        </doc>
      </field>

      <segments>
        <header required="true">
          <entry type="file-properties"/>
        </header>
        <body/>
      </segments>
    </command>

    <!-- - Command: file.deliver - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="deliver" code="0xb" label="notify the client of a consumer message">
      <doc>
        This command delivers a staged file message to the client, via a consumer. In the
        asynchronous message delivery model, the client starts a consumer using the consume command,
        then the server responds with Deliver commands as and when messages arrive for that
        consumer.
      </doc>

      <rule name="redelivery-tracking">
        <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 non-processable (possibly
          causing client applications to abort), and move the message to a dead letter queue.
        </doc>
      </rule>

      <implement role="client" handle="MUST" />

      <field name="consumer-tag" type="str8" />

      <field name="delivery-tag" type="uint64" >
        <doc>
          The server-assigned and session-specific delivery tag
        </doc>

        <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>
      </field>

      <field name="redelivered" type="bit" label="Indicate possible duplicate delivery">
        <doc>
          This boolean flag indicates that the message may have been previously delivered to this
          or another client.
        </doc>
      </field>

      <field name="exchange" type="exchange.name">
        <doc>
          Specifies the name of the exchange that the message was originally published to.
        </doc>
      </field>

      <field name="routing-key" type="str8" label="Message routing key">
        <doc>
          Specifies the routing key name specified when the message was published.
        </doc>
      </field>

      <field name="identifier" type="str8" label="staging identifier">
        <doc>
          This is the staging identifier of the message to deliver. The message must have been
          staged. Note that a server can send the Deliver command asynchronously without waiting for
          staging to finish.
        </doc>
      </field>
    </command>

    <!-- - Command: file.ack - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="ack" code="0xc" label="acknowledge one or more messages">
      <doc>
        This command acknowledges one or more messages delivered via the Deliver command. The client
        can ask to confirm a single message or a set of messages up to and including a specific
        message.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="delivery-tag" type="uint64" >
        <doc>
          The identifier of the message being acknowledged
        </doc>
        <rule name="session-local">
          <doc>
            The delivery tag is valid only within the session from which the message was received.
            i.e. A client MUST NOT receive a message on one session and then acknowledge it on
            another.
          </doc>
        </rule>
      </field>

      <field name="multiple" type="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 command. 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="validation">
          <doc>
            The server MUST validate that a non-zero delivery-tag refers to an delivered message,
            and raise an exception if this is not the case.
          </doc>
        </rule>
      </field>
    </command>

    <!-- - Command: file.reject  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="reject" code="0xd" label="reject an incoming message">
      <doc>
        This command allows a client to reject a message. It can be used to return untreatable
        messages to their original queue. Note that file content is staged before delivery, so the
        client will not use this command to interrupt delivery of a large message.
      </doc>

      <rule name="server-interpretation">
        <doc>
          The server SHOULD interpret this command as meaning that the client is unable to process
          the message at this time.
        </doc>
      </rule>

      <rule name="not-selection">
        <doc>
          A client MUST NOT use this command as a means of selecting messages to process. A rejected
          message MAY be discarded or dead-lettered, not necessarily passed to another client.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />

      <field name="delivery-tag" type="uint64">
        <doc>
        the identifier of the message to be rejected
        </doc>
        <rule name="session-local">
          <doc>
            The delivery tag is valid only within the session from which the message was received.
            i.e. A client MUST NOT receive a message on one session and then reject it on another.
          </doc>
        </rule>
      </field>

      <field name="requeue" type="bit" label="requeue the message">
        <doc>
          If this field is zero, the message will be discarded. If this bit is 1, the server will
          attempt to requeue the message.
        </doc>

        <rule name="requeue-strategy">
          <doc>
            The server MUST NOT deliver the message to the same client within the context of the
            current session. 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>
        </rule>
      </field>
    </command>

  </class>

  <!-- == Class: stream ======================================================================== -->

  <class name="stream" code="0xa" label="work with streaming content">
    <doc>
      The stream class provides commands that support multimedia streaming. The stream class uses
      the following semantics: one message is one packet of data; delivery is unacknowledged and
      unreliable; the consumer can specify quality of service parameters that the server can try to
      adhere to; lower-priority messages may be discarded in favor of high priority messages.
    </doc>

    <doc type="grammar">
      stream  = C:QOS S:QOS-OK
              / C:CONSUME S:CONSUME-OK
              / C:CANCEL
              / C:PUBLISH content
              / S:RETURN
              / S:DELIVER content
    </doc>

    <rule name="overflow-discard">
      <doc>
        The server SHOULD discard stream messages on a priority basis if the queue size exceeds some
        configured limit.
      </doc>
    </rule>

    <rule name="priority-levels">
      <doc>
        The server MUST implement at least 2 priority levels for stream messages, where priorities
        0-4 and 5-9 are treated as two distinct levels. The server MAY implement up to 10 priority
        levels.
      </doc>
    </rule>

    <rule name="acknowledgement-support">
      <doc>
        The server MUST implement automatic acknowledgements on stream content. That is, as soon as
        a message is delivered to a client via a Deliver command, the server must remove it from the
        queue.
      </doc>
    </rule>

    <role name="server" implement="MAY" />
    <role name="client" implement="MAY" />

    <!--  These are the properties for a Stream content  -->
    <struct name="stream-properties" size="4" code="0x1" pack="2">
      <field name="content-type" type="str8" label="MIME content type" />
      <field name="content-encoding" type="str8" label="MIME content encoding" />
      <field name="headers" type="map" label="message header field table" />
      <field name="priority" type="uint8" label="message priority, 0 to 9" />
      <field name="timestamp" type="datetime" label="message timestamp" />
    </struct>

    <domain name="return-code" type="uint16" label="return code from server">
      <doc>
        The return code. The AMQP return codes are defined by this enum.
      </doc>
      <enum>
        <choice name="content-too-large" value="311">
          <doc>
            The client attempted to transfer content larger than the server could accept.
          </doc>
        </choice>

        <choice name="no-route" value="312">
          <doc>
            The exchange cannot route a message, most likely due to an invalid routing key. Only
            when the mandatory flag is set.
          </doc>
        </choice>

        <choice name="no-consumers" value="313">
          <doc>
            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>
        </choice>
      </enum>
    </domain>

    <!-- - Command: stream.qos - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="qos" code="0x1" label="specify quality of service">
      <doc>
        This command requests a specific quality of service. The QoS can be specified for the
        current session or for all sessions on the connection. The particular properties and
        semantics of a qos command always depend on the content class semantics. Though the qos
        command could in principle apply to both peers, it is currently meaningful only for the
        server.
      </doc>

      <implement role="server" handle="MUST" />

      <response name="qos-ok" />

      <field name="prefetch-size" type="uint32" label="pre-fetch 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 within the session. Pre-fetching gives a performance improvement. This field
          specifies the pre-fetch window size in octets. May be set to zero, meaning "no specific
          limit". Note that other pre-fetch limits may still apply.
        </doc>
      </field>

      <field name="prefetch-count" type="uint16" label="pre-fetch window in messages">
        <doc>
          Specifies a pre-fetch 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
          pre-fetch windows (and those at the session and connection level) allow it.
        </doc>
      </field>

      <field name="consume-rate" type="uint32" label="transfer rate in octets/second">
        <doc>
          Specifies a desired transfer rate in octets per second. This is usually determined by the
          application that uses the streaming data. A value of zero means "no limit", i.e. as
          rapidly as possible.
        </doc>

        <rule name="ignore-prefetch">
          <doc>
            The server MAY ignore the pre-fetch values and consume rates, depending on the type of
            stream and the ability of the server to queue and/or reply it.
          </doc>
        </rule>

        <rule name="drop-by-priority">
          <doc>
            The server MAY drop low-priority messages in favor of high-priority messages.
          </doc>
        </rule>
      </field>

      <field name="global" type="bit" label="apply to entire connection">
        <doc>
          By default the QoS settings apply to the current session only. If this field is set, they
          are applied to the entire connection.
        </doc>
      </field>
    </command>

    <!-- - Command: stream.qos-ok  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="qos-ok" code="0x2" label="confirm the requested qos">
      <doc>
        This command 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>

      <implement role="client" handle="MUST" />
    </command>

    <!-- - Command: stream.consume - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="consume" code="0x3" label="start a queue consumer">
      <doc>
        This command asks the server to start a "consumer", which is a transient request for
        messages from a specific queue. Consumers last as long as the session they were created on,
        or until the client cancels them.
      </doc>

      <rule name="min-consumers">
        <doc>
          The server SHOULD support at least 16 consumers per queue, unless the queue was declared
          as private, and ideally, impose no limit except as defined by available resources.
        </doc>
      </rule>

      <rule name="priority-based-delivery">
        <doc>
          Streaming applications SHOULD use different sessions to select different streaming
          resolutions. AMQP makes no provision for filtering and/or transforming streams except on
          the basis of priority-based selective delivery of individual messages.
        </doc>
      </rule>

      <implement role="server" handle="MUST" />

      <response name="consume-ok" />

      <field name="queue" type="queue.name">
        <doc>
          Specifies the name of the queue to consume from.
        </doc>

        <exception name="queue-exists-if-empty" error-code="not-allowed">
          <doc>
            If the queue name in this command is empty, the server MUST raise an exception.
          </doc>
        </exception>
      </field>

      <field name="consumer-tag" type="str8">
        <doc>
          Specifies the identifier for the consumer. The consumer tag is local to a connection, so
          two clients can use the same consumer tags.
        </doc>

        <exception name="not-existing-consumer" error-code="not-allowed">
          <doc>
            The tag MUST NOT refer to an existing consumer. If the client attempts to create two
            consumers with the same non-empty tag the server MUST raise an exception.
          </doc>
        </exception>

        <exception name="not-empty-consumer-tag" error-code="not-allowed">
          <doc>
            The client MUST NOT specify a tag that is empty or blank.
          </doc>
          <doc type="scenario">
            Attempt to create a consumers with an empty tag.
          </doc>
        </exception>
      </field>

      <field name="no-local" type="bit">
        <doc>If the no-local field is set the server will not send messages to the connection that
        published them.</doc>
      </field>

      <field name="exclusive" type="bit" label="request exclusive access">
        <doc>
          Request exclusive consumer access, meaning only this consumer can access the queue.
        </doc>

        <exception name="in-use" error-code="resource-locked">
          <doc>
            If the server cannot grant exclusive access to the queue when asked, - because there are
            other consumers active - it MUST raise an exception with return code 405
            (resource locked).
          </doc>
        </exception>
      </field>

      <field name="nowait" type="bit" label="do not send a reply command">
        <doc>
          If set, the server will not respond to the command. The client should not wait for a reply
          command. If the server could not complete the command it will raise an exception.
        </doc>
      </field>

      <field name="arguments" type="map" label="arguments for consuming">
        <doc>
          A set of arguments for the consume. The syntax and semantics of these arguments depends on
          the providers implementation.
        </doc>
      </field>
    </command>

    <!-- - Command: stream.consume-ok  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="consume-ok" code="0x4" label="confirm a new consumer">
      <doc>
        This command provides the client with a consumer tag which it may use in commands that work
        with the consumer.
      </doc>

      <implement role="client" handle="MUST" />

      <field name="consumer-tag" type="str8">
        <doc>
          Holds the consumer tag specified by the client or provided by the server.
        </doc>
      </field>
    </command>

    <!-- - Command: stream.cancel  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="cancel" code="0x5" label="end a queue consumer">
      <doc>
        This command cancels a consumer. Since message delivery is asynchronous the client may
        continue to receive messages for a short while after cancelling a consumer. It may process
        or discard these as appropriate.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="consumer-tag" type="str8" />
    </command>

    <!-- - Command: stream.publish - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="publish" code="0x6" label="publish a message">
      <doc>
        This command 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 as
        appropriate.
      </doc>

      <implement role="server" handle="MUST" />

      <field name="exchange" type="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 an exception.
        </doc>

        <rule name="default">
          <doc>
            The server MUST accept a blank exchange name to mean the default exchange.
          </doc>
        </rule>

        <exception name="refusal" error-code="not-implemented">
          <doc>
            The exchange MAY refuse stream content in which case it MUST respond with an exception.
          </doc>
        </exception>
      </field>

      <field name="routing-key" type="str8" 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" type="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 command. If
          this flag is zero, the server silently drops the message.
        </doc>

        <rule name="implementation">
          <doc>
            The server SHOULD implement the mandatory flag.
          </doc>
        </rule>
      </field>

      <field name="immediate" type="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 command. If this flag is zero, the server will queue the message, but with
          no guarantee that it will ever be consumed.
        </doc>

        <rule name="implementation">
          <doc>
            The server SHOULD implement the immediate flag.
          </doc>
        </rule>
      </field>

      <segments>
        <header required="true">
          <entry type="stream-properties"/>
        </header>
        <body/>
      </segments>
    </command>

    <!-- - Command: stream.return  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="return" code="0x7" label="return a failed message">
      <doc>
        This command 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>

      <implement role="client" handle="MUST" />

      <field name="reply-code" type="return-code" />

        <field name="reply-text" type="str8" label="The localized reply text.">
            <doc>
                The localized reply text. This text can be logged as an aid to resolving issues.
            </doc>
        </field>

      <field name="exchange" type="exchange.name">
        <doc>
          Specifies the name of the exchange that the message was originally published to.
        </doc>
      </field>

      <field name="routing-key" type="str8" label="Message routing key">
        <doc>
          Specifies the routing key name specified when the message was published.
        </doc>
      </field>

      <segments>
        <header required="true">
          <entry type="stream-properties"/>
        </header>
        <body/>
      </segments>
    </command>

    <!-- - Command: stream.deliver - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

    <command name="deliver" code="0x8" label="notify the client of a consumer message">
      <doc>
        This command delivers a message to the client, via a consumer. In the asynchronous message
        delivery model, the client starts a consumer using the Consume command, then the server
        responds with Deliver commands as and when messages arrive for that consumer.
      </doc>

      <implement role="client" handle="MUST" />

      <field name="consumer-tag" type="str8" />

      <field name="delivery-tag" type="uint64">
        <doc>
          The server-assigned and session-specific delivery tag
        </doc>
        <rule name="session-local">
          <doc>
            The delivery tag is valid only within the session from which the message was received.
            i.e. A client MUST NOT receive a message on one session and then acknowledge it on
            another.
          </doc>
        </rule>
      </field>

      <field name="exchange" type="exchange.name">
        <doc>
          Specifies the name of the exchange that the message was originally published to.
        </doc>
      </field>

      <field name="queue" type="queue.name" required="true">
        <doc>
          Specifies the name of the queue that the message came from. Note that a single session can
          start many consumers on different queues.
        </doc>
      </field>

      <segments>
        <header required="true">
          <entry type="stream-properties"/>
        </header>
        <body/>
      </segments>
    </command>

  </class>

</amqp>