2026-03-28 16:54:11 +11:00
# ifndef ANSULT_H
# define ANSULT_H
# define ANSULT_API __declspec(dllexport)
# pragma once
# include "LabVIEWHeader/extcode.h"
# include <map>
# include <string>
# include "ANSLicense.h"
# include <CkRest.h>
# include "CkAuthGoogle.h"
# include "CkByteData.h"
# include <CkAuthAws.h>
# include <CkXml.h>
# include <CkCrypt2.h>
# include <CkSocket.h>
# include <opencv2/opencv.hpp>
# include <thread>
# include <atomic>
namespace ANSCENTER {
class ANSULT_API ANSUtilities {
private :
// Protects all shared mutable data
mutable std : : recursive_mutex _mutex ;
bool _isUnlockCodeValid { false } ;
bool _isLicenseValid { false } ;
std : : string _licenseKey ;
std : : string _unlockCode ;
std : : string _proxyHost ;
int _proxyPort { 0 } ;
std : : string _proxyUsername ;
std : : string _proxyPassword ;
bool _bProxy { false } ;
std : : string _fireBaseSessionToken ;
bool _bTls { true } ;
int _port { 443 } ;
bool _bAutoReconnect { true } ;
bool _isAWSConnected { false } ;
// Google Cloud Storage Authentication
CkAuthGoogle _authGoogle ;
bool _isAuthenticated { false } ;
SPDLogger & _logger = SPDLogger : : GetInstance ( " ANSUtilities " , false ) ;
std : : chrono : : system_clock : : time_point tokenGeneratedTime ;
bool tokenInitialized = false ;
static const int TOKEN_EXPIRY_SECONDS = 3600 ;
public :
ANSUtilities ( ) ;
~ ANSUtilities ( ) ;
[ [ nodiscard ] ] bool Initialize ( const std : : string & licenseKey ) ;
void CheckLicense ( ) ;
void CheckUnlockCode ( ) ;
[ [ nodiscard ] ] bool SetServerProxy ( const std : : string & proxyHost , int proxyPort , const std : : string & proxyUsername , const std : : string & proxyPassword ) ;
[ [ nodiscard ] ] std : : string GetFirebaseCloudMessageAcccessToken ( std : : string privateKey ) ;
//AWS SNS Functions
[ [ nodiscard ] ] std : : string CreateAWSSNSTopic ( const std : : string & topicName ) ; // Will return the ARN of the topic
[ [ nodiscard ] ] bool DeleteAWSSNSTopic ( const std : : string & topicARN ) ; // Will return the ARN of the topic
[ [ nodiscard ] ] std : : string ListAWSSNSTopic ( ) ; // Will return the list ARN of the topic in string with ; concatenated
[ [ nodiscard ] ] std : : string SubcribeSMSPhoneNumber ( const std : : string & topicARN , const std : : string & phoneNumber ) ;
[ [ nodiscard ] ] std : : string SubscribeEmailAddress ( const std : : string & topicARN , const std : : string & emailAddress ) ;
[ [ nodiscard ] ] std : : string SendMessageToTopic ( const std : : string & topicARN , const std : : string & subjectContent , const std : : string & messageContent ) ; // Return the message ID
[ [ nodiscard ] ] std : : string SendMessageToPhoneNumber ( const std : : string & phoneNumber , const std : : string & messageContent ) ; // Return the message ID
// Google Cloud Storage Upload using Chilkat
[ [ nodiscard ] ] bool AuthenticateGCS ( const std : : string & jsonKeyString ) ;
[ [ nodiscard ] ] bool UploadMatToGCS ( const std : : string & bucketName , const std : : string & objectName , const cv : : Mat & image ) ;
[ [ nodiscard ] ] bool UploadMatToGCS ( const std : : string & bucketName , const std : : string & objectName , unsigned char * jpeg_string , int32 bufferLength ) ;
[ [ nodiscard ] ] static bool CheckUnlockCode_S ( ) ;
[ [ nodiscard ] ] static std : : string AESEncryption ( const std : : string & inputString , const std : : string & inputKey ) ;
[ [ nodiscard ] ] static std : : string AESDecryption ( const std : : string & encryptString , const std : : string & inputKey ) ;
[ [ nodiscard ] ] static std : : string MD5HashFile ( const std : : string & inputFilePath ) ;
// SMTP for office360 email sending
[ [ nodiscard ] ] static bool SendEmail ( const std : : string & smtpServer , int port ,
const std : : string & userName , const std : : string & password ,
const std : : string & subjectContent ,
const std : : string & bodyHTMLContent ,
const std : : string & bodyTextContent ,
const std : : string & fromEmailSender ,
const std : : vector < std : : string > & toEmails ,
const std : : vector < std : : string > & ccEmails ,
const std : : vector < std : : string > & bccEmails ) ;
// Restart PC
[ [ nodiscard ] ] static bool RestartPC ( ) ;
2026-03-31 14:10:21 +11:00
// Convert a UTF-8 encoded string to UTF-16LE byte string.
// Useful for LabVIEW which can display UTF-16LE Unicode text on Windows.
static std : : string ConvertUTF8ToUTF16LE ( const std : : string & utf8Str ) ;
// Decode JSON Unicode escape sequences (\uXXXX) to UTF-16LE byte string.
// Input: ASCII string with \uXXXX escapes (e.g., "\\u6c5f\\u6771 599")
// Output: UTF-16LE byte string for LabVIEW display.
static std : : string DecodeJsonUnicodeToUTF16LE ( const std : : string & escapedStr ) ;
// Convert a UTF-16LE byte string to UTF-8.
// Useful for receiving Unicode text from LabVIEW and converting to UTF-8 for internal processing.
static std : : string ConvertUTF16LEToUTF8 ( const char * utf16leBytes , int byteLen ) ;
2026-03-28 16:54:11 +11:00
} ;
// Connection bundle for pool
struct S3Connection {
CkRest rest ;
CkSocket socket ;
CkAuthAws authAws ;
} ;
class ANSULT_API ANSAWSS3 {
private :
bool _isUnlockCodeValid { false } ;
bool _isLicenseValid { false } ;
bool _bConnected { false } ;
bool _bAwsPath { true } ; // true = virtual-hosted (AWS), false = path-style (MinIO)
std : : string _licenseKey ;
std : : string _unlockCode ;
// ── Connection pool (replaces single _rest/_socket/_authAws) ──
std : : mutex _poolMutex ;
std : : vector < std : : unique_ptr < S3Connection > > _pool ;
// ── Config (read-only after setup, protected by _configMutex) ──
std : : mutex _configMutex ;
std : : string _fullAWSURL ; // AWS S3 service URL
bool _bTls { true } ;
int _port { 443 } ;
bool _bAutoReconnect { true } ;
std : : string _serviceName ;
std : : string _bucketRegion ;
std : : string _baseDomain ;
std : : string _accessKey ;
std : : string _secretKey ;
bool _authReady { false } ;
// Proxy settings
std : : string _proxyHost ;
int _proxyPort { 0 } ;
std : : string _proxyUsername ;
std : : string _proxyPassword ;
bool _bProxy { false } ;
SPDLogger & _logger = SPDLogger : : GetInstance ( " ANSAWSS3 " , false ) ;
// Pool helpers
std : : unique_ptr < S3Connection > CreateConnection ( ) ;
std : : unique_ptr < S3Connection > AcquireConnection ( ) ;
void ReleaseConnection ( std : : unique_ptr < S3Connection > conn ) ;
std : : string ExtractFileName ( const std : : string & filePath ) ;
std : : string GetContentType ( const std : : string & filePath ) ;
// Background retry
std : : thread _retryThread ;
std : : atomic < bool > _stopRetry { false } ;
std : : atomic < bool > _retryInProgress { false } ;
void StopRetry ( ) ;
void RetryLoop ( ) ;
bool TryConnect ( bool & awsPath ) ;
public :
ANSAWSS3 ( ) ;
~ ANSAWSS3 ( ) ;
[ [ nodiscard ] ] bool Initialize ( const std : : string & licenseKey ) ;
void CheckLicense ( ) ;
void CheckUnlockCode ( ) ;
[ [ nodiscard ] ] bool SetServerProxy ( const std : : string & proxyHost , int proxyPort , const std : : string & proxyUsername , const std : : string & proxyPassword ) ;
// Returns: 1 = connected, 0 = failed (bad auth/URL), 2 = no internet (background retry started)
[ [ nodiscard ] ] int Connect ( const std : : string & baseDomain , const std : : string & bucketRegion , const std : : string & serviceName , int port , bool bTls , bool autoReconnect , bool & awsPath ) ;
[ [ nodiscard ] ] bool SetAuthentication ( const std : : string & accessKey , const std : : string & secretKey ) ;
[ [ nodiscard ] ] std : : vector < std : : string > ListBuckets ( ) ;
[ [ nodiscard ] ] std : : vector < std : : string > ListBucketObjects ( const std : : string & bucketName ) ;
[ [ nodiscard ] ] std : : vector < std : : string > ListBucketObjectsWithPrefix ( const std : : string & bucketName , const std : : string & prefix ) ;
[ [ nodiscard ] ] bool CreateBucket ( const std : : string & bucketName ) ;
[ [ nodiscard ] ] bool DeleteBucket ( const std : : string & bucketName ) ;
[ [ nodiscard ] ] bool CreateFolder ( const std : : string & bucketName , const std : : string & prefix ) ;
[ [ nodiscard ] ] bool DeleteFolder ( const std : : string & bucketName , const std : : string & prefix ) ;
[ [ nodiscard ] ] bool DeleteBucketObject ( const std : : string & bucketName , const std : : string & objectName ) ;
[ [ nodiscard ] ] std : : string GetBucketRegion ( const std : : string & bucketName ) ;
// Upload data to AWS S3
[ [ nodiscard ] ] bool UploadTextData ( const std : : string & bucketName , const std : : string & textFilePath , std : : string & uploadedFilePath ) ;
[ [ nodiscard ] ] bool UploadFileStream ( const std : : string & bucketName , const std : : string & dataFilePath , std : : string & uploadedFilePath ) ;
[ [ nodiscard ] ] bool UploadBinaryData ( const std : : string & bucketName , const std : : string & dataFilePath , std : : string & uploadedFilePath ) ;
[ [ nodiscard ] ] bool UploadPrefixBinaryData ( const std : : string & bucketName , const std : : string & prefix , const std : : string & dataFilePath , const std : : string & objectName , std : : string & uploadedFilePath ) ;
[ [ nodiscard ] ] bool UploadMultipartData ( const std : : string & bucketName , const std : : string & dataFilePath , std : : string & uploadedFilePath , int partSize = 5242880 ) ;
[ [ nodiscard ] ] bool UploadPrefixMultipartData ( const std : : string & bucketName , const std : : string & prefix , const std : : string & dataFilePath , const std : : string & fileName , std : : string & uploadedFilePath , int partSize = 5242880 ) ;
[ [ nodiscard ] ] bool UploadPrefixJpegImage ( const std : : string & bucketName , const std : : string & prefix , unsigned char * jpeg_string , int32 bufferLength , const std : : string & fileName , std : : string & uploadedFilePath ) ;
[ [ nodiscard ] ] bool UploadJpegImage ( const std : : string & bucketName , unsigned char * jpeg_string , int32 bufferLength , const std : : string & fileName , std : : string & uploadedFilePath ) ;
[ [ nodiscard ] ] bool DownloadFile ( const std : : string & bucketName , const std : : string & objectName , const std : : string & saveFilePath ) ;
} ;
}
extern " C " ANSULT_API int CreateANSUtilityHandle ( ANSCENTER : : ANSUtilities * * Handle , const char * licenseKey ) ;
extern " C " ANSULT_API int ReleaseANSUtilityHandle ( ANSCENTER : : ANSUtilities * * Handle ) ;
extern " C " ANSULT_API int GetFCMAccessToken ( ANSCENTER : : ANSUtilities * * Handle , const char * privateKey , LStrHandle accessToken ) ;
extern " C " ANSULT_API int CreateAWSSNSTopic ( ANSCENTER : : ANSUtilities * * Handle , const char * snsTopicName , LStrHandle arnTopic ) ;
extern " C " ANSULT_API int DeleteAWSSNSTopic ( ANSCENTER : : ANSUtilities * * Handle , const char * arnTopic ) ;
extern " C " ANSULT_API int ListASWTopics ( ANSCENTER : : ANSUtilities * * Handle , LStrHandle arnTopics ) ;
extern " C " ANSULT_API int AESEncryption ( const char * inputString , const char * inputKey , LStrHandle encryptionMessage ) ;
extern " C " ANSULT_API int AESDecryption ( const char * encryptedString , const char * inputKey , LStrHandle decryptionMessage ) ;
extern " C " ANSULT_API int MD5HashFile ( const char * filePath , LStrHandle decryptionMessage ) ;
extern " C " ANSULT_API int SubcribeSMSPhoneNumberAWSSNSTopic ( ANSCENTER : : ANSUtilities * * Handle , const char * snsTopicName , const char * phoneNumber , LStrHandle subscribedARN ) ;
extern " C " ANSULT_API int SubcribeEmailAddressAWSSNSTopic ( ANSCENTER : : ANSUtilities * * Handle , const char * snsTopicName , const char * emailAddress , LStrHandle subscribedARN ) ;
extern " C " ANSULT_API int SendMessageToAWSSNSTopic ( ANSCENTER : : ANSUtilities * * Handle , const char * snsTopicName , const char * subjectContent , const char * messageContent , LStrHandle messageId ) ;
extern " C " ANSULT_API int SendMessageToPhoneNumber ( ANSCENTER : : ANSUtilities * * Handle , const char * phoneNumber , const char * messageContent , LStrHandle messageId ) ;
extern " C " ANSULT_API int GetFCMAccessTokenCpp ( ANSCENTER : : ANSUtilities * * Handle , const char * privateKey , std : : string & accessToken ) ;
extern " C " ANSULT_API int CreateAWSSNSTopicCpp ( ANSCENTER : : ANSUtilities * * Handle , const char * snsTopicName , std : : string & arnTopic ) ;
extern " C " ANSULT_API int SubcribeSMSPhoneNumberAWSSNSTopicCpp ( ANSCENTER : : ANSUtilities * * Handle , const char * snsTopicName , const char * phoneNumber , std : : string & subscribedARN ) ;
extern " C " ANSULT_API int SubcribeEmailAddressAWSSNSTopicCpp ( ANSCENTER : : ANSUtilities * * Handle , const char * snsTopicName , const char * emailAddress , std : : string & subscribedARN ) ;
extern " C " ANSULT_API int SendMessageToAWSSNSTopicCpp ( ANSCENTER : : ANSUtilities * * Handle , const char * snsTopicName , const char * subjectContent , const char * messageContent , std : : string & messageId ) ;
extern " C " ANSULT_API int SendMessageToPhoneNumberCpp ( ANSCENTER : : ANSUtilities * * Handle , const char * phoneNumber , const char * messageContent , std : : string & messageId ) ;
extern " C " ANSULT_API int ListASWTopicsCpp ( ANSCENTER : : ANSUtilities * * Handle , std : : string & arnTopics ) ;
// Static functions
extern " C " ANSULT_API int AESEncryptionCpp ( const char * inputString , const char * inputKey , std : : string & encryptedString ) ;
extern " C " ANSULT_API int AESDecryptionCpp ( const char * encryptedString , const char * inputKey , std : : string & decryptionMessage ) ;
// Google Cloud Storage
extern " C " ANSULT_API int SetupServerProxy ( ANSCENTER : : ANSUtilities * * Handle , const char * hostName , int port , const char * userName , const char * passWord ) ;
extern " C " ANSULT_API int AuthenticateGCS ( ANSCENTER : : ANSUtilities * * Handle , const char * jsonKeyString ) ;
extern " C " ANSULT_API int UploadMatToGCS ( ANSCENTER : : ANSUtilities * * Handle , const char * bucketName , const char * objectName , unsigned char * jpeg_string , int32 bufferLength ) ;
extern " C " ANSULT_API int UploadImageToGCS ( ANSCENTER : : ANSUtilities * * Handle , const char * bucketName , const char * objectName , cv : : Mat image ) ;
extern " C " ANSULT_API int SendEmail ( const char * smtpServer , int port ,
const char * userName , const char * password ,
const char * title , const char * bodyHTMLContent ,
const char * bodyTextContent ,
const char * fromEmailSender ,
const char * toEmails ,
const char * ccEmails ,
const char * bccEmails ) ;
extern " C " ANSULT_API int RebootSystem ( ) ;
2026-03-31 14:10:21 +11:00
// Unicode conversion utilities for LabVIEW
2026-03-31 21:52:47 +11:00
extern " C " ANSULT_API int ANSConvertUTF8ToUTF16LE ( const char * utf8Str , LStrHandle result , int includeBOM = 1 ) ;
2026-03-31 14:10:21 +11:00
extern " C " ANSULT_API int ANSDecodeJsonUnicodeToUTF16LE ( const char * escapedStr , LStrHandle result ) ;
extern " C " ANSULT_API int ANSConvertUTF16LEToUTF8 ( const unsigned char * utf16leBytes , int byteLen , LStrHandle result ) ;
2026-03-28 16:54:11 +11:00
// AWS S3 class
extern " C " ANSULT_API int CreateANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * licenseKey ) ;
extern " C " ANSULT_API int ReleaseANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle ) ;
extern " C " ANSULT_API int ConnectANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * baseDomain , const char * bucketRegion , const char * serviceName , int port , int bTls , int autoReconnect , int * awsPath ) ;
extern " C " ANSULT_API int SetProxyANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * proxyHost , int proxyPort , const char * proxyUsername , const char * proxyPassword ) ;
extern " C " ANSULT_API int SetAuthenticationANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * accessKey , const char * secretKey ) ;
extern " C " ANSULT_API int ListBucketANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , std : : string & bucketList ) ;
extern " C " ANSULT_API int ListBucketObjectsANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , std : : string & bucketNameList ) ;
extern " C " ANSULT_API int ListBucketObjectsWithPrefixANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix , std : : string & bucketNameList ) ;
extern " C " ANSULT_API int GetRegionANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , std : : string & region ) ;
extern " C " ANSULT_API int ListBucketANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , LStrHandle bucketList ) ;
extern " C " ANSULT_API int ListBucketObjectsANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , LStrHandle bucketNameList ) ;
extern " C " ANSULT_API int ListBucketObjectsWithPrefixANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix , LStrHandle bucketNameList ) ;
extern " C " ANSULT_API int GetRegionANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , LStrHandle region ) ;
extern " C " ANSULT_API int CreateBucketANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName ) ;
extern " C " ANSULT_API int DeleteBucketANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName ) ;
extern " C " ANSULT_API int CreateBucketPrefixANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix ) ;
extern " C " ANSULT_API int DeleteBucketPrefixANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix ) ;
extern " C " ANSULT_API int DeleteBucketObjectANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * bucketObject ) ;
extern " C " ANSULT_API int UploadTextDataANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * textDataPath , LStrHandle uploadedFilePath ) ;
extern " C " ANSULT_API int UploadBinaryDataANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * binaryDataPath , LStrHandle uploadedFilePath ) ;
extern " C " ANSULT_API int UploadFileStreamDataANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * fileDataPath , LStrHandle uploadedFilePath ) ;
extern " C " ANSULT_API int UploadMultiPartDataANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * fileDataPath , int fileSize , LStrHandle uploadedFilePath ) ;
extern " C " ANSULT_API int UploadJpegImageANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , unsigned char * jpeg_string , int32 bufferLength , const char * fileName , LStrHandle uploadedFilePath ) ;
extern " C " ANSULT_API int UploadPrefixBinaryDataANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix , const char * binaryDataPath , const char * objectName , LStrHandle uploadedFilePath ) ;
extern " C " ANSULT_API int UploadPrefixMultiPartDataANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix , const char * fileDataPath , const char * objectName , int fileSize , LStrHandle uploadedFilePath ) ;
extern " C " ANSULT_API int UploadPrefixJpegImageANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix , unsigned char * jpeg_string , int32 bufferLength , const char * fileName , LStrHandle uploadedFilePath ) ;
extern " C " ANSULT_API int DownloadFileStreamANSAWSHandle ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * objectName , const char * savedFilePath ) ;
// C++ test APIs (use std::string& instead of LStrHandle)
extern " C " ANSULT_API int UploadTextDataANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * textDataPath , std : : string & uploadedFilePath ) ;
extern " C " ANSULT_API int UploadBinaryDataANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * binaryDataPath , std : : string & uploadedFilePath ) ;
extern " C " ANSULT_API int UploadFileStreamDataANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * fileDataPath , std : : string & uploadedFilePath ) ;
extern " C " ANSULT_API int UploadMultiPartDataANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * fileDataPath , int fileSize , std : : string & uploadedFilePath ) ;
extern " C " ANSULT_API int UploadJpegImageANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , unsigned char * jpeg_string , int32 bufferLength , const char * fileName , std : : string & uploadedFilePath ) ;
extern " C " ANSULT_API int UploadPrefixBinaryDataANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix , const char * binaryDataPath , const char * objectName , std : : string & uploadedFilePath ) ;
extern " C " ANSULT_API int UploadPrefixMultiPartDataANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix , const char * fileDataPath , const char * objectName , int fileSize , std : : string & uploadedFilePath ) ;
extern " C " ANSULT_API int UploadPrefixJpegImageANSAWSHandle_CPP ( ANSCENTER : : ANSAWSS3 * * Handle , const char * bucketName , const char * prefix , unsigned char * jpeg_string , int32 bufferLength , const char * fileName , std : : string & uploadedFilePath ) ;
# endif