#include "idl_types.h"

/*
  the base dcerpc packet definitions - not traditionally coded as IDL,
  but given that pidl can handle it nicely it simplifies things a lot
  to do it this way

  see http://www.opengroup.org/onlinepubs/9629399/chap12.htm for packet
  layouts
*/
import "misc.idl";

interface dcerpc
{
	typedef struct {
		uint16 context_id;
		uint8 num_transfer_syntaxes;
		ndr_syntax_id abstract_syntax;
		ndr_syntax_id transfer_syntaxes[num_transfer_syntaxes];
	} dcerpc_ctx_list;

	typedef [public] struct {
		uint16 max_xmit_frag;
		uint16 max_recv_frag;
		uint32 assoc_group_id;
		uint8  num_contexts;
		dcerpc_ctx_list ctx_list[num_contexts];
		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
	} dcerpc_bind;

	const uint8 DCERPC_REQUEST_LENGTH = 24;

	typedef struct {
	} dcerpc_empty;

	typedef [nodiscriminant] union {
		[default] dcerpc_empty empty;
		[case(LIBNDR_FLAG_OBJECT_PRESENT)] GUID object;
	} dcerpc_object;

	typedef struct {
		uint32 alloc_hint;
		uint16 context_id;
		uint16 opnum;
		[switch_is(ndr->flags & LIBNDR_FLAG_OBJECT_PRESENT)] dcerpc_object object;
		[flag(NDR_ALIGN8)]    DATA_BLOB _pad;
		[flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier;
	} dcerpc_request;

	const int DCERPC_BIND_REASON_ASYNTAX                 = 1;
	const int DCERPC_BIND_PROVIDER_REJECT                = 2;
	const int DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED = 4;
	const int DCERPC_BIND_REASON_INVALID_AUTH_TYPE       = 8;

	typedef struct {
		uint16 result;
		uint16 reason;
		ndr_syntax_id syntax;
	} dcerpc_ack_ctx;

	typedef struct {
		uint16 max_xmit_frag;
		uint16 max_recv_frag;
		uint32 assoc_group_id;
		[value(strlen(secondary_address)+1)] uint16 secondary_address_size;
		[charset(DOS)] uint8 secondary_address[secondary_address_size];
		[flag(NDR_ALIGN4)]    DATA_BLOB _pad1;
		uint8 num_results;
		dcerpc_ack_ctx ctx_list[num_results];
		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
	} dcerpc_bind_ack;

	typedef struct {
		uint32 num_versions;
		uint32 versions[num_versions];
	} dcerpc_bind_nak_versions;

	typedef [nodiscriminant] union {
		[case(DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED)] dcerpc_bind_nak_versions v;
		[default] ;
	} dcerpc_bind_nak_versions_ctr;

	typedef struct {
		uint16 reject_reason;
		[switch_is(reject_reason)] dcerpc_bind_nak_versions_ctr versions;
	} dcerpc_bind_nak;

	const uint8 DCERPC_RESPONSE_LENGTH = 24;

	typedef struct {
		uint32 alloc_hint;
		uint16 context_id;
		uint8 cancel_count;
		[flag(NDR_ALIGN8)]    DATA_BLOB _pad;
		[flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier;
	} dcerpc_response;

	typedef [v1_enum] enum {
		DCERPC_NCA_S_COMM_FAILURE		= 0x1C010001,
		DCERPC_NCA_S_OP_RNG_ERROR		= 0x1C010002,
		DCERPC_NCA_S_UNKNOWN_IF			= 0x1C010003,
		DCERPC_NCA_S_WRONG_BOOT_TIME		= 0x1C010006,
		DCERPC_NCA_S_YOU_CRASHED		= 0x1C010009,
		DCERPC_NCA_S_PROTO_ERROR		= 0x1C01000B,
		DCERPC_NCA_S_OUT_ARGS_TOO_BIG		= 0x1C010013,
		DCERPC_NCA_S_SERVER_TOO_BUSY		= 0x1C010014,
		DCERPC_NCA_S_FAULT_STRING_TOO_LARGE	= 0x1C010015,
		DCERPC_NCA_S_UNSUPPORTED_TYPE		= 0x1C010017,
		DCERPC_NCA_S_FAULT_INT_DIV_BY_ZERO	= 0x1C000001,
		DCERPC_NCA_S_FAULT_ADDR_ERROR		= 0x1C000002,
		DCERPC_NCA_S_FAULT_FP_DIV_BY_ZERO	= 0x1C000003,
		DCERPC_NCA_S_FAULT_FP_UNDERFLOW		= 0x1C000004,
		DCERPC_NCA_S_FAULT_FP_OVERRFLOW		= 0x1C000005,
		DCERPC_NCA_S_FAULT_INVALID_TAG		= 0x1C000006,
		DCERPC_NCA_S_FAULT_INVALID_BOUND	= 0x1C000007,
		DCERPC_NCA_S_FAULT_RPC_VERSION_MISMATCH	= 0x1C000008,
		DCERPC_NCA_S_FAULT_UNSPEC_REJECT	= 0x1C000009,
		DCERPC_NCA_S_FAULT_BAD_ACTID		= 0x1C00000A,
		DCERPC_NCA_S_FAULT_WHO_ARE_YOU_FAILED	= 0x1C00000B,
		DCERPC_NCA_S_FAULT_MANAGER_NOT_ENTERED	= 0x1C00000C,
		DCERPC_NCA_S_FAULT_CANCEL		= 0x1C00000D,
		DCERPC_NCA_S_FAULT_ILL_INST		= 0x1C00000E,
		DCERPC_NCA_S_FAULT_FP_ERROR		= 0x1C00000F,
		DCERPC_NCA_S_FAULT_INT_OVERFLOW		= 0x1C000010,
		DCERPC_NCA_S_UNUSED_1C000011		= 0x1C000011,
		DCERPC_NCA_S_FAULT_UNSPEC		= 0x1C000012,
		DCERPC_NCA_S_FAULT_REMOTE_COMM_FAILURE	= 0x1C000013,
		DCERPC_NCA_S_FAULT_PIPE_EMPTY		= 0x1C000014,
		DCERPC_NCA_S_FAULT_PIPE_CLOSED		= 0x1C000015,
		DCERPC_NCA_S_FAULT_PIPE_ORDER		= 0x1C000016,
		DCERPC_NCA_S_FAULT_PIPE_DISCIPLINE	= 0x1C000017,
		DCERPC_NCA_S_FAULT_PIPE_COMM_ERROR	= 0x1C000018,
		DCERPC_NCA_S_FAULT_PIPE_MEMORY		= 0x1C000019,
		DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH	= 0x1C00001A,
		DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY	= 0x1C00001B,
		DCERPC_NCA_S_INVALID_PRES_CONTEXT_ID	= 0x1C00001C,
		DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL	= 0x1C00001D,
		DCERPC_NCA_S_UNUSED_1C00001E		= 0x1C00001E,
		DCERPC_NCA_S_INVALID_CHECKSUM		= 0x1C00001F,
		DCERPC_NCA_S_INVALID_CRC		= 0x1C000020,
		DCERPC_NCA_S_FAULT_USER_DEFINED		= 0x1C000021,
		DCERPC_NCA_S_FAULT_TX_OPEN_FAILED	= 0x1C000022,
		DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR	= 0x1C000023,
		DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND	= 0x1C000024,
		DCERPC_NCA_S_FAULT_NO_CLIENT_STUB	= 0x1C000025
	} dcerpc_nca_status;

	const int DCERPC_FAULT_OP_RNG_ERROR       = 0x1c010002;
	const int DCERPC_FAULT_UNK_IF             = 0x1c010003;
	const int DCERPC_FAULT_NDR                = 0x000006f7;
	const int DCERPC_FAULT_INVALID_TAG        = 0x1c000006;
	const int DCERPC_FAULT_CONTEXT_MISMATCH   = 0x1c00001a;
	const int DCERPC_FAULT_OTHER              = 0x00000001;
	const int DCERPC_FAULT_ACCESS_DENIED      = 0x00000005;
	const int DCERPC_FAULT_CANT_PERFORM       = 0x000006d8;
	const int DCERPC_FAULT_SEC_PKG_ERROR      = 0x00000721;

	/* we return this fault when we haven't yet run the test
	   to see what fault w2k3 returns in this case */
	const int DCERPC_FAULT_TODO         = 0x00000042;

	typedef struct {
		uint32 alloc_hint;
		uint16 context_id;
		uint8 cancel_count;
		dcerpc_nca_status status;
		[flag(NDR_REMAINING)] DATA_BLOB _pad;
	} dcerpc_fault;

	/* the auth types we know about */
	typedef [enum8bit] enum {
		DCERPC_AUTH_TYPE_NONE     = 0,
		/* this seems to be not krb5! */
		DCERPC_AUTH_TYPE_KRB5_1   = 1,
		DCERPC_AUTH_TYPE_SPNEGO   = 9,
		DCERPC_AUTH_TYPE_NTLMSSP  = 10,
		DCERPC_AUTH_TYPE_KRB5     = 16,
		DCERPC_AUTH_TYPE_DPA      = 17,
		DCERPC_AUTH_TYPE_MSN      = 18,
		DCERPC_AUTH_TYPE_DIGEST   = 21,
		DCERPC_AUTH_TYPE_SCHANNEL = 68,
		DCERPC_AUTH_TYPE_MSMQ     = 100,
		DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM = 200
	} dcerpc_AuthType;

	typedef [enum8bit] enum {
		DCERPC_AUTH_LEVEL_NONE      = 1,
		DCERPC_AUTH_LEVEL_CONNECT   = 2,
		DCERPC_AUTH_LEVEL_CALL      = 3,
		DCERPC_AUTH_LEVEL_PACKET    = 4,
		DCERPC_AUTH_LEVEL_INTEGRITY = 5,
		DCERPC_AUTH_LEVEL_PRIVACY   = 6
	} dcerpc_AuthLevel;

	const uint8 DCERPC_AUTH_LEVEL_DEFAULT	= DCERPC_AUTH_LEVEL_CONNECT;

	typedef [public] struct {
		dcerpc_AuthType auth_type;
		dcerpc_AuthLevel auth_level;
		uint8  auth_pad_length;
		uint8  auth_reserved;
		uint32 auth_context_id;
		[flag(NDR_REMAINING)] DATA_BLOB credentials;
	} dcerpc_auth;

	const uint8 DCERPC_AUTH_TRAILER_LENGTH = 8;

	typedef [public] struct {
		[value(0)]	      uint32    _pad;
		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
	} dcerpc_auth3;

	typedef [public] struct {
		[value(0)]	      uint32    _pad;
		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
	} dcerpc_orphaned;

	typedef [public] struct {
		[value(0)]	      uint32    _pad;
		[flag(NDR_REMAINING)] DATA_BLOB auth_info;
	} dcerpc_co_cancel;

	typedef [public] struct {
		uint32 version;
		uint32 id;
	} dcerpc_cl_cancel;

	typedef [public] struct {
		uint32 version;
		uint32 id;
		boolean32 server_is_accepting;
	} dcerpc_cancel_ack;

	typedef [public] struct {
		uint32 version;
		uint8 _pad1;
		uint16 window_size;
		uint32 max_tdsu;
		uint32 max_frag_size;
		uint16 serial_no;
		uint16 selack_size;
		uint32 selack[selack_size];
	} dcerpc_fack;

	typedef [public] struct {
	} dcerpc_ack;

	typedef [public] struct {
	} dcerpc_ping;

	typedef [public] struct {
	} dcerpc_shutdown;

	typedef [public] struct {
	} dcerpc_working;

	/* RTS data structures */
	typedef [public] struct {
		GUID		Cookie;
	} RTSCookie;

	typedef [v1_enum,public] enum {
		RTS_IPV4	= 0,
		RTS_IPV6	= 1
	} AddressType;

	typedef [nodiscriminant] union {
		[case(RTS_IPV4)] ipv4address	ClientAddressIPV4;
		[case(RTS_IPV6)] ipv6address	ClientAddressIPV6;
	} ClientAddressType;

	typedef [public] struct {
		AddressType					AddressType;
		[switch_is(AddressType)] ClientAddressType	ClientAddress;
		uint8						Padding[12];
	} ClientAddress;

	typedef [v1_enum, public] enum {
		FDClient	= 0,
		FDInProxy	= 1,
		FDServer	= 2,
		FDOutProxy	= 3
	} ForwardDestination;

	typedef [public] struct {
		uint32		BytesReceived;
		uint32		AvailableWindow;
		RTSCookie	ChannelCookie;
	} FlowControlAcknowledgment;

	/* RTS commands */

	/* RTS command: 0x0 */
	typedef [public] struct {
		[range(0x2000,0x40000)] uint32	ReceiveWindowSize;
	} dcerpc_rts_cmd_ReceiveWindowSize;

	/* RTS command: 0x1 */
	typedef [public] struct {
		FlowControlAcknowledgment	Ack;
	} dcerpc_rts_cmd_FlowControlAck;

	/* RTS command: 0x2 */
	typedef [public] struct {
		[range(0x1D4C0,0xDBBA00)] uint32	ConnectionTimeout;
	} dcerpc_rts_cmd_ConnectionTimeout;

	/* RTS command: 0x3 */
	typedef [public] struct {
		RTSCookie	Cookie;
	} dcerpc_rts_cmd_Cookie;

	/* RTS command: 0x4 */
	typedef [public] struct {
		[range(0x20000,0x80000000)] uint32	ChannelLifetime;
	} dcerpc_rts_cmd_ChannelLifetime;

	/* RTS command: 0x5 */
	typedef [public] struct {
		uint32		ClientKeepalive;
	} dcerpc_rts_cmd_ClientKeepalive;

	/* RTS command: 0x6 */
	typedef [public] struct {
		uint32		Version;
	} dcerpc_rts_cmd_Version;

	/* RTS command: 0x7 */
	typedef [public] struct {
	} dcerpc_rts_cmd_Empty;

	/* RTS command: 0x8 */
	typedef [public] struct {
		[range(0x0,0xFFFF)] uint32	ConformanceCount;
		uint8				Padding[ConformanceCount];
	} dcerpc_rts_cmd_Padding;

	/* RTS command: 0x9 */
	typedef [public] struct {
	} dcerpc_rts_cmd_NegativeANCE;

	/* RTS Command: 0xA */
	typedef [public] struct {
	} dcerpc_rts_cmd_ANCE;

	/* RTS command: 0xB */
	typedef [public] struct {
		ClientAddress	ClientAddress;
	} dcerpc_rts_cmd_ClientAddress;

	/* RTS command: 0xC */
	typedef [public] struct {
		RTSCookie	AssociationGroupId;
	} dcerpc_rts_cmd_AssociationGroupId;

	/* RTS command: 0xD */
	typedef [public] struct {
		ForwardDestination	ForwardDestination;
	} dcerpc_rts_cmd_Destination;

	/* RTS command: 0xE */
	typedef [public] struct {
		uint32	PingTrafficSent;
	} dcerpc_rts_cmd_PingTrafficSentNotify;

	typedef [nodiscriminant] union {
		[case(0x0)] dcerpc_rts_cmd_ReceiveWindowSize		ReceiveWindowSize;
		[case(0x1)] dcerpc_rts_cmd_FlowControlAck		FlowControlAck;
		[case(0x2)] dcerpc_rts_cmd_ConnectionTimeout		ConnectionTimeout;
		[case(0x3)] dcerpc_rts_cmd_Cookie			Cookie;
		[case(0x4)] dcerpc_rts_cmd_ChannelLifetime		ChannelLifetime;
		[case(0x5)] dcerpc_rts_cmd_ClientKeepalive		ClientKeepalive;
		[case(0x6)] dcerpc_rts_cmd_Version			Version;
		[case(0x7)] dcerpc_rts_cmd_Empty			Empty;
		[case(0x8)] dcerpc_rts_cmd_Padding			Padding;
		[case(0x9)] dcerpc_rts_cmd_NegativeANCE			NegativeANCE;
		[case(0xA)] dcerpc_rts_cmd_ANCE				ANCE;
		[case(0xB)] dcerpc_rts_cmd_ClientAddress		ClientAddress;
		[case(0xC)] dcerpc_rts_cmd_AssociationGroupId		AssociationGroupId;
		[case(0xD)] dcerpc_rts_cmd_Destination			Destination;
		[case(0xE)] dcerpc_rts_cmd_PingTrafficSentNotify	PingTrafficSentNotify;
	} dcerpc_rts_cmds;

	typedef [public] struct {
		uint32						CommandType;
		[switch_is(CommandType)] dcerpc_rts_cmds	Command;
	} dcerpc_rts_cmd;

	/* The RTS flags */
	typedef [public, bitmap16bit] bitmap {
		RTS_FLAG_NONE			=	0x0000,
		RTS_FLAG_PING			=	0x0001,
		RTS_FLAG_OTHER_CMD		=	0x0002,
		RTS_FLAG_RECYCLE_CHANNEL	=	0x0004,
		RTS_FLAG_IN_CHANNEL		=	0x0008,
		RTS_FLAG_OUT_CHANNEL		=	0x0010,
		RTS_FLAG_EOF			=	0x0020,
		RTS_FLAG_ECHO			=	0x0040
	} dcerpc_rts_flags;

	typedef [public] struct {
		dcerpc_rts_flags	Flags;
		uint16			NumberOfCommands;
		dcerpc_rts_cmd		Commands[NumberOfCommands];
	} dcerpc_rts;

	typedef [enum8bit] enum {
		DCERPC_PKT_REQUEST     =  0,	/* Ordinary request. */
		DCERPC_PKT_PING        =  1,	/* Connectionless is server alive ? */
		DCERPC_PKT_RESPONSE    =  2,	/* Ordinary reply. */
		DCERPC_PKT_FAULT       =  3,	/* Fault in processing of call. */
		DCERPC_PKT_WORKING     =  4,	/* Connectionless reply to a ping when server busy. */
		DCERPC_PKT_NOCALL      =  5,	/* Connectionless reply to a ping when server has lost part of clients call. */
		DCERPC_PKT_REJECT      =  6,	/* Refuse a request with a code. */
		DCERPC_PKT_ACK         =  7,	/* Connectionless client to server code. */
		DCERPC_PKT_CL_CANCEL   =  8,	/* Connectionless cancel. */
		DCERPC_PKT_FACK        =  9,	/* Connectionless fragment ack. Both client and server send. */
		DCERPC_PKT_CANCEL_ACK  = 10,	/* Server ACK to client cancel request. */
		DCERPC_PKT_BIND        = 11,	/* Bind to interface. */
		DCERPC_PKT_BIND_ACK    = 12,	/* Server ack of bind. */
		DCERPC_PKT_BIND_NAK    = 13,	/* Server nack of bind. */
		DCERPC_PKT_ALTER       = 14,	/* Alter auth. */
		DCERPC_PKT_ALTER_RESP  = 15,	/* Reply to alter auth. */
		DCERPC_PKT_AUTH3       = 16, 	/* not the real name!  this is undocumented! */
		DCERPC_PKT_SHUTDOWN    = 17,	/* Server to client request to shutdown. */
		DCERPC_PKT_CO_CANCEL   = 18,	/* Connection-oriented cancel request. */
		DCERPC_PKT_ORPHANED    = 19,	/* Client telling server it's aborting a partially sent request or telling server to stop sending replies. */
		DCERPC_PKT_RTS	       = 20	/* RTS packets used in ncacn_http */
	} dcerpc_pkt_type;

	typedef [nodiscriminant] union {
		[case(DCERPC_PKT_REQUEST)]    dcerpc_request  request;
		[case(DCERPC_PKT_PING)] 	  dcerpc_ping ping;
		[case(DCERPC_PKT_RESPONSE)]   dcerpc_response response;
		[case(DCERPC_PKT_FAULT)]	  dcerpc_fault fault;
		[case(DCERPC_PKT_WORKING)]	  dcerpc_working working;
		[case(DCERPC_PKT_NOCALL)]     dcerpc_fack nocall;
		[case(DCERPC_PKT_REJECT)]     dcerpc_fault reject;
		[case(DCERPC_PKT_ACK)]        dcerpc_ack ack;
		[case(DCERPC_PKT_CL_CANCEL)]  dcerpc_cl_cancel cl_cancel;
		[case(DCERPC_PKT_FACK)]       dcerpc_fack fack;
		[case(DCERPC_PKT_CANCEL_ACK)] dcerpc_cancel_ack cancel_ack;
		[case(DCERPC_PKT_BIND)]       dcerpc_bind     bind;
		[case(DCERPC_PKT_BIND_ACK)]   dcerpc_bind_ack bind_ack;
		[case(DCERPC_PKT_BIND_NAK)]   dcerpc_bind_nak bind_nak;
		[case(DCERPC_PKT_ALTER)]      dcerpc_bind     alter;
		[case(DCERPC_PKT_ALTER_RESP)] dcerpc_bind_ack alter_resp;
		[case(DCERPC_PKT_SHUTDOWN)]   dcerpc_shutdown shutdown;
		[case(DCERPC_PKT_CO_CANCEL)]  dcerpc_co_cancel co_cancel;
		[case(DCERPC_PKT_ORPHANED)]   dcerpc_orphaned orphaned;
		[case(DCERPC_PKT_AUTH3)]      dcerpc_auth3    auth3;
		[case(DCERPC_PKT_RTS)]	      dcerpc_rts      rts;
	} dcerpc_payload;

	/* pfc_flags values */
	const uint8 DCERPC_PFC_FLAG_FIRST		= 0x01; /* First fragment */
	const uint8 DCERPC_PFC_FLAG_LAST		= 0x02; /* Last fragment */
	const uint8 DCERPC_PFC_FLAG_PENDING_CANCEL	= 0x04; /* Cancel was pending at sender */
	const uint8 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN	= DCERPC_PFC_FLAG_PENDING_CANCEL; /* depends on the pdu type */
	const uint8 DCERPC_PFC_FLAG_CONC_MPX		= 0x10; /* supports concurrent multiplexing of a single connection. */
	const uint8 DCERPC_PFC_FLAG_DID_NOT_EXECUTE	= 0x20; /* on a fault it means the server hasn't done anything */
	const uint8 DCERPC_PFC_FLAG_MAYBE		= 0x40; /* `maybe' call semantics requested */
	const uint8 DCERPC_PFC_FLAG_OBJECT_UUID		= 0x80; /* on valid guid is in the optional object field */

	/* these offsets are needed by the signing code */
	const uint8 DCERPC_PFC_OFFSET      =  3;
	const uint8 DCERPC_DREP_OFFSET     =  4;
	const uint8 DCERPC_FRAG_LEN_OFFSET =  8;
	const uint8 DCERPC_AUTH_LEN_OFFSET = 10;

	/* little-endian flag */
	const uint8 DCERPC_DREP_LE  = 0x10;

	typedef [public] struct {
		uint8 rpc_vers;	        /* RPC version */
		uint8 rpc_vers_minor;   /* Minor version */
		dcerpc_pkt_type ptype;  /* Packet type */
		uint8 pfc_flags;        /* Fragmentation flags */
		uint8 drep[4];	        /* NDR data representation */
		uint16 frag_length;     /* Total length of fragment */
		uint16 auth_length;     /* authenticator length */
		uint32 call_id;	        /* Call identifier */
		[switch_is(ptype)] dcerpc_payload u;
	} ncacn_packet;

	typedef [public] struct {
		uint8 rpc_vers;		/* RPC version (4) */
		uint8 ptype;
		uint8 pfc_flags;
		uint8 ncadg_flags;
		uint8 drep[3];
		uint8 serial_high;
		GUID object;
		GUID iface;
		GUID activity;
		uint32 server_boot; /* Server boot time */
		uint32 iface_version;
		uint32 seq_num;
		uint16 opnum;
		uint16 ihint;
		uint16 ahint;
		uint16 len;
		uint16 fragnum;
		uint8 auth_proto;
		uint8 serial_low;
		[switch_is(ptype)] dcerpc_payload u;
	} ncadg_packet;
}