/***************************************************************************
  $RCSfile: libchipcard.h,v $
                             -------------------
    cvs         : $Id: libchipcard.h,v 1.14 2003/02/17 04:17:46 aquamaniac Exp $
    begin       : Sun Mar 10 2002
    copyright   : (C) 2002 by Martin Preuss
    email       : martin@libchipcard.de


 ***************************************************************************
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
 *   MA  02111-1307  USA                                                   *
 *                                                                         *
 ***************************************************************************/

/**
 * @file libchipcard.h
 *
 * @short Contains the C API of LibChipCard.
 * @ingroup c_api
 */


#ifndef LIBCHIPCARD_H
#define LIBCHIPCARD_H

#include <chipcard/ctcore_public.h>

#ifdef __cplusplus
extern "C" {
#endif


#define CHIPCARD_SUCCESS                   0
#define CHIPCARD_ERROR_INVALID             1
#define CHIPCARD_ERROR_BUFFER              2
#define CHIPCARD_ERROR_CARD_REMOVED        3

#define CHIPCARD_ERROR_NO_REQUEST          4
#define CHIPCARD_ERROR_NO_MESSAGE          5
#define CHIPCARD_ERROR_BAD_CHANNEL_STATUS  6
#define CHIPCARD_ERROR_NO_COMMANDS         7
#define CHIPCARD_ERROR_NO_CONFIG           8
#define CHIPCARD_ERROR_UNREACHABLE         9
#define CHIPCARD_ERROR_DRIVER              10
#define CHIPCARD_ERROR_NO_READER           11
#define CHIPCARD_ERROR_COMMAND_NOT_FOUND   12
#define CHIPCARD_ERROR_BAD_RESPONSE        13
#define CHIPCARD_ERROR_NO_CARD             14
#define CHIPCARD_ERROR_ABORTED             15
#define CHIPCARD_ERROR_INTERRUPTED         16
#define CHIPCARD_ERROR_NO_TRANSPORT        17
#define CHIPCARD_ERROR_INTERNAL            99

#define CHIPCARD_STATUS_INSERTED        CTREADERSTATUS_INSERTED
#define CHIPCARD_STATUS_CONNECTED       CTREADERSTATUS_CONNECTED
#define CHIPCARD_STATUS_PROCESSOR       CTREADERSTATUS_PROCESSOR
#define CHIPCARD_STATUS_LOCKED_BY_OTHER CTREADERSTATUS_LOCKED_BY_OTHER

#define CHIPCARD_READERFLAGS_KEYPAD  CTREADERFLAGS_KEYPAD
#define CHIPCARD_READERFLAGS_DISPLAY CTREADERFLAGS_DISPLAY


CHIPCARD_API struct CHIPCARD_READERDESCRSTRUCT {
  unsigned int flags;
  char name[64];
  char type[64];
};
CHIPCARD_API typedef struct CHIPCARD_READERDESCRSTRUCT CHIPCARD_READERDESCR;

/**
 * @name Organisational Stuff
 *
 * Well, I don't know in which group to put these functions otherwise ;-)
 */
/*@{*/
/**
 * LibChipCard works asynchronously. Most functions only create a request
 * and enqueue it internally. Every time you call this function the enqueued
 * requests are actually send to the corresponding servers. So you will
 * never get an answer to a request if you don't call this function.
 * However, when using the C++ interface (@ref CTCard and derived classes)
 * then this function is called internally.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 */
CHIPCARD_API int ChipCard_Work();

/**
 * This function allows adding a card server to the internal list thus
 * bypassing the configuration files. This function is depracated and may
 * seize to exist in future versions, so please don't rely on it.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param addr address of the card server (either 3-dot notation or host name)
 * if port is "-1" then this must be the path to the unix domain socket
 * @param port port the server is listening on. If this is "-1" then unix
 * domain sockets will be used, in this case the address should be the path to
 * the socket file.
 */
CHIPCARD_API int ChipCard_AddServer(const char *addr,
				    int port);

/**
 * This function can be used to free a reader description received upon
 * @ref ChipCard_CheckConnect(). You should alway free such a reader
 * description by using this function.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 */
CHIPCARD_API void ChipCard_ReaderDescr_free(CHIPCARD_READERDESCR *rd);
/*@}*/

/**
 * @name Initialisation and Deinitialisation
 *
 * The functions in this group only need to be called hen you are using the
 * C interface only. The C++ classes automatically call them.
 */
/*@{*/
/**
 * This function initializes LibChipCard. It loads all necessary configuration
 * and command files. No communication with any server is done here.
 * This function can be called directly (and must be called if only C code
 * is to be used), but if you are using the C++ API (@ref CTCard and derived
 * classes) then this will be called internally when needed.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param configfile path and name of the client configuration file to use. If
 * this is NULL then the hardcoded default file will be used
 * @param section the name of the configuration section which is to be used.
 * If this is NULL (which is recommended) then the root of the configuration
 * file will be used.
 */
CHIPCARD_API int ChipCard_Init(const char *configfile,
			       const char *section);

/**
 * This functions shuts down LibChipCard (the client part). It should be
 * called when the program exits. However, when using the C++ API then
 * it will be called internally when needed.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 */
CHIPCARD_API void ChipCard_Fini();
/*@}*/

/**
 * @name Configuration File Based APDU Engine
 *
 * The functions of this group are allow looking up APDU commands.
 * This engine allows adjusting LibChipCard to special cards and readers
 * without recompiling LibChipCard.
 */
/*@{*/

/**
 * This functions tries to lookup a card command (APDU) based on the
 * type of the reader and the card. This allows adjusting commands to
 * special cards or readers without the need for recompilation of
 * LibChipCard.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param command name of the command (like "select_mf")
 * @param readertype type of the reader (either "towitoko", "kobil",
 * "cyberjack" or "other")
 * @param buffer buffer to store the complete path and name of the command
 * found
 * @param bufferlen size of the buffer provided
 */
CHIPCARD_API int ChipCard_LocateCommand(const char *command,
					const char *readertype,
					const char *cardtype,
					char *buffer,
					int bufferlen);

/**
 * Checks whether a given command exists. You can provide a full path here
 * (including readertype and card type separated by "/")
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param command full path of the command to check for
 */
CHIPCARD_API int ChipCard_ExistsCommand(const char *command);

/*@}*/

/**
 * @name General Request and Response Handling
 *
 * This group contains functions which can be applied to any pending request.
 */
/*@{*/

/**
 * Each request can be identified by its request id. This function here
 * checks whether there is a response to the given request pending.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid unique request id of the request to check for responses
 */
CHIPCARD_API int ChipCard_CheckResponse(int requestid);

/**
 * If you issued a request and for any reason want to withdraw it (thereby
 * telling LibChipCard that you're no longer interested in a response) then
 * you are expected to call this function. It frees all ressources occupied
 * by the request. All future responses to this request which may arrive
 * after withdrawing the request are ignored.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param request id unique request id
 */
CHIPCARD_API void ChipCard_WithdrawRequest(int requestid);
/*@}*/


/**
 * @name Requests
 *
 * LibChipCard works asynchronously. Nearly all actions you want LibChipCard
 * to take are in form of a request. Generally you call a request function
 * (ChipCard_RequestXYZ()), then @ref ChipCard_Work() (repeatedly until a
 * response arrives) and the appropriate check function (ChipCard_CheckXYZ()).
 * The check function is the one that returns the results of a request (if
 * it successfully returns)
 */
/*@{*/

/**
 * This function requests the allocation of a card reader. A card reader must
 * be allocated in order to use it. After you have finished using the reader
 * you should release it by @ref ChipCard_RequestReleaseReader().
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid pointer to an integer variable to receive the request id
 * This is only altered if this function returns without an error
 * @param tid the id of the terminal. You can get this by using
 * @ref ChipCard_RequestFindReader() or @ref ChipCard_RequestWaitReader().
 */
CHIPCARD_API int ChipCard_RequestAllocReader(int *requestid,
					     unsigned int tid);

/**
 * This function checks whether there is a response for the request.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid unique request id assigned by the matching request
 * function
 * @param thdl pointer to an integer variable to receive the terminal handle
 * This one is not to be confused with the tid param given to
 * @ref ChipCard_RequestAllocReader()
 * @param rd pointer to a pointer to receive the description of the allocated
 * reader. You are expected to call @ref ChipCard_ReaderDescr_free() when
 * you don't need this description anymore (you take over ownership for this
 * item)
 */
CHIPCARD_API int ChipCard_CheckAllocReader(int requestid,
					   int *thdl,
					   CHIPCARD_READERDESCR **rd);

/**
 *This function requests to release a reader. You are expected to call this
 * function when you are finished using the reader in order to free
 * ressources allocated locally by the reader.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid pointer to an integer variable to receive the request id
 * This is only altered if this function returns without an error
 */
CHIPCARD_API int ChipCard_RequestReleaseReader(int *requestid,
					       unsigned int tid);

/**
 * This function checks whether there is a response for the request.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid unique request id assigned by the matching request
 * function
 */
CHIPCARD_API int ChipCard_CheckReleaseReader(int requestid);

/**
 * This function requests connecting a card to the given reader.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid pointer to an integer variable to receive the request id
 * This is only altered if this function returns without an error
 * @param thdl terminal handle assigned by @ref ChipCard_RequestAllocReader()
 */
CHIPCARD_API int ChipCard_RequestConnect(int *requestid,
					 unsigned int thdl);

/**
 * This function checks whether there is a response for the request.
 * All return parameters are only modified upon successfull return.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid unique request id assigned by the matching request
 * function
 * @param result pointer to an integer variable to receive the result of the
 * connect request. Please note that the return value of this function can
 * be "OK" even if the connect itself did not succeed. This is because
 * the return value of this function only tells you whether the request has
 * been answered. You need this parameter here to check for the result of the
 * connect itself.
 * @param atrbuffer pointer to a buffer which is filled upon successful return
 * with the ATR ("Answer To Reset") string returned by a chipcard upon
 * connect. This ATR is normally used to identify/verify the card type since
 * it is quite unique.
 * @param atrbufferlength pointer to variable that tells this function about
 * the size of the buffer supplied. Upon return that variable contains the
 * number of bytes actually used by the ATR string. It is guaranteed to
 * never exceed the entry value. Please note that the ATR string is a binary
 * string not terminated by a zero byte (unlike ASCIIZ strings).
 */
CHIPCARD_API int ChipCard_CheckConnect(int requestid,
				       int *result,
				       char *atrbuffer,
				       int *atrbufferlength);

/**
 * This function requests disconnecting a card in the given reader.
 * The card is reset by this function, so that any security status is
 * guaranteed to be cleared upon successfull disconnect.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid pointer to an integer variable to receive the request id
 * This is only altered if this function returns without an error
 * @param thdl terminal handle assigned by @ref ChipCard_RequestAllocReader()
 */
CHIPCARD_API int ChipCard_RequestDisconnect(int *requestid,
					    unsigned int thdl);


/**
 * This function checks whether there is a response for the request.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid unique request id assigned by the matching request
 * function
 * @param result pointer to an integer variable to receive the result of the
 * disconnect request. Please note that the return value of this function can
 * be "OK" even if the disconnect itself did not succeed. This is because
 * the return value of this function only tells you whether the request has
 * been answered. You need this parameter here to check for the result of the
 * disconnect itself.
 */
CHIPCARD_API int ChipCard_CheckDisconnect(int requestid,
					  int *result);


/**
 * This function requests executing a raw APDU on the card in the given
 * reader.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid pointer to an integer variable to receive the request id
 * This is only altered if this function returns without an error
 * @param thdl terminal handle assigned by @ref ChipCard_RequestAllocReader()
 * @param sendBuffer pointer to the buffer containing the APDU to be executed
 * @param sendBufferLength length of the send buffer
 */
CHIPCARD_API int ChipCard_RequestCommand(int *requestid,
					 unsigned int thdl,
					 const char *sendBuffer,
					 int sendBufferLength);

/**
 * This function requests executing an APDU by using the configuration file
 * driven APDU engine. You have to supply the name of the command to be
 * executed and optionally some parameters (depending on the command).
 * E.g. the command "select_df" needs the file id of the DF to select.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid pointer to an integer variable to receive the request id
 * This is only altered if this function returns without an error
 * @param thdl terminal handle assigned by @ref ChipCard_RequestAllocReader()
 * @param command c-string containing the name of the command to be executed
 * @param argc number of parameters following. This parameter is followed
 * by 0 or more parameters (like the function fprintf()).
 */
CHIPCARD_API int ChipCard_RequestCommand2(int *requestid,
					  unsigned int thdl,
					  const char *command,
					  int argc, ...);

/**
 * This function checks for the result of @ref ChipCard_RequestCommand() and
 * @ref ChipCard_RequestCommand2().
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid unique request id assigned by the matching request
 * function
 * @param result pointer to an integer variable to receive the result of the
 * command request. Please note that the return value of this function can
 * be "OK" even if the command itself did not succeed. This is because
 * the return value of this function only tells you whether the request has
 * been answered. You need this parameter here to check for the result of the
 * command itself.
 * @param recvBuffer pointer to a buffer for the answer from the card. It
 * must at least have space for two bytes (the two result codes of any APDU)
 * @param recvBufferLength pointer to an integer variable initially
 * containing the length of the buffer provided. Upon return this holds the
 * number of bytes actually stored in the buffer. This is guaranteed to never
 * exceed the initial value.
 */
CHIPCARD_API int ChipCard_CheckCommand(int requestid,
				       int *result,
				       char *recvBuffer,
				       int *recvBufferLength);

/**
 * This function requests to find a reader by drivertype, readertype and/or
 * readerflags.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid pointer to an integer variable to receive the request id
 * This is only altered if this function returns without an error
 * @param readerType (e.g. "towitoko","kobil", "cyberjack")
 * or -1 to match all)
 * @param readerFlags (any ORed combination of CHIPCARD_READERFLAGS_KEYPAD and
 * CHIPCARD_READERFLAGS_DISPLAY)
 * @param readerFlagsMask may hold the same values as the readerFlags, but
 * this one here is interpreted as a mask. E.g. if this is zero then all
 * readerflags match.
 */
CHIPCARD_API int ChipCard_RequestFindReader(int *requestid,
					    const char *readerType,
					    unsigned int readerFlags,
					    unsigned int readerFlagsMask);

/**
 * This function checks whether there is a response for the request.
 * Since a FindReader request is send to all registered servers you should
 * call this function repeatedly (intermixed with @ref ChipCard_Work())until
 * CHIPCARD_ERROR_NO_REQUEST is returned. If you have found a reader
 * before CHIPCARD_ERROR_NO_REQUEST is returned then you should withdraw the
 * request by calling @ref ChipCard_WithdrawRequest().
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid unique request id assigned by the matching request
 * function
 * @param readerbuffer a pointer to an integer array to receive the ids
 * of the terminals found. Each of the entries returned in this buffer can
 * be fed to @ref ChipCard_RequestAllocReader.
 * @param readerBufferLength size of the buffer (as the number of integer
 * values the array contains, not the size in bytes!)
 */
CHIPCARD_API int ChipCard_CheckFindReader(int requestid,
					  unsigned int *readerbuffer,
					  int *readerBufferLength);
/**
 * This function requests the status of a card reader.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid pointer to an integer variable to receive the request id
 * This is only altered if this function returns without an error
 * @param thdl terminal handle assigned by @ref ChipCard_RequestAllocReader()
 */
CHIPCARD_API int ChipCard_RequestStatReader(int *requestid,
					    int thdl);

/**
 * This function checks whether there is a response for the request.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid unique request id assigned by the matching request
 * function
 * @param result pointer to an integer variable to receive the result of the
 * stat request. Please note that the return value of this function can
 * be "OK" even if the stat itself did not succeed. This is because
 * the return value of this function only tells you whether the request has
 * been answered. You need this parameter here to check for the result of the
 * stat itself.
 * @param status pointer to a variable to receive the status of the reader
 * upon successfull return. It holds any OR combination of CHIPCARD_STATUS_XYZ
 * values.
 * @param atrbuffer pointer to a buffer which is filled upon successful return
 * with the ATR ("Answer To Reset") string returned by a chipcard upon
 * connect. This ATR is normally used to identify/verify the card type since
 * it is quite unique.
 * @param atrlen pointer to variable that tells this function about
 * the size of the buffer supplied. Upon return that variable contains the
 * number of bytes actually used by the ATR string. It is guaranteed to
 * never exceed the entry value. Please note that the ATR string is a binary
 * string not terminated by a zero byte (unlike ASCIIZ strings).
 */
CHIPCARD_API int ChipCard_CheckStatReader(int requestid,
					  int *result,
					  unsigned int *status,
					  char *atrbuffer,
					  int *atrlen);
/**
 * This function requests to wait until a matching reader is available.
 * This function is quite similar to @ref ChipCard_RequestFindReader(), but
 * it allows to specify the status of the reader to be matched in addition
 * to the type. As soon as the server discovers a reader which matches this
 * pattern it will send a notification which can be received via
 * @ref ChipCard_CheckWaitReader. Please note that this request must be
 * stopped by calling @ref ChipCard_StopWaitReader when you don't want to
 * wait for another reader.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid pointer to an integer variable to receive the request id
 * This is only altered if this function returns without an error
 * @param mustChange if this parameter is true then the status of a reader
 * must change to allow matching. If this flag is zero then the server
 * will notify you about each reader which already matches the given criteria.
 * One example on how to use this feature is the <i>kvkd</i>, the daemon for
 * German medical cards. It waits for a card (with this flag on), then reads
 * this card and continues checking. This way it only gets notifications
 * whenever the status of a reader changes.
 * @param readerType (e.g. "towitoko","kobil", "cyberjack")
 * or -1 to match all)
 * @param readerFlags (any ORed combination of CHIPCARD_READERFLAGS_KEYPAD and
 * CHIPCARD_READERFLAGS_DISPLAY)
 * @param readerFlagsMask may hold the same values as the readerFlags, but
 * this one here is interpreted as a mask. E.g. if this is zero then all
 * readerflags match.
 * @param status status to match. The combination of this parameter and the
 * statusMask determines the status to be matched.
 */
CHIPCARD_API int ChipCard_RequestWaitReader(int *requestid,
					    int mustChange,
					    const char *readerType,
					    unsigned int readerFlags,
					    unsigned int readerFlagsMask,
					    unsigned int status,
					    unsigned int statusMask);

/**
 * This function checks whether there is a response for the request.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @return result code (0==ok, all other values are CHIPCARD_ERROR_XYZ values)
 * @param requestid unique request id assigned by the matching request
 * function
 * @param tid pointer to a variable to receive the id of a matching terminal.
 * This is only altered if the function successfully returns.
 * @param status pointer to a variable to receive the current status of the
 * terminal identified by tid
 * @param readerflags pointer to a variable to receive the readerflags of the
 * terminal identified by tid
 */
CHIPCARD_API int ChipCard_CheckWaitReader(int requestid,
					  int *tid,
					  unsigned int *status,
					  unsigned int *readerflags);

/**
 * This function stops waiting for further reader notifications induced by
 * @ref ChipCard_RequestWaitReader(). It releases all ressources allocated
 * by this request.
 * @ingroup c_api
 * @author Martin Preuss<martin@libchipcard.de>
 * @param prevRequest unique request id assigned by the matching request
 * function
 */
CHIPCARD_API int ChipCard_StopWaitReader(int prevRequest);
/*@}*/

/**
 * @internal
 */
CHIPCARD_API int ChipCard_RequestPing(int *requestid,
				      int serviceid);
/**
 * @internal
 */
CHIPCARD_API int ChipCard_CheckPing(int requestid);


#ifdef __cplusplus
}
#endif

#endif



