search

Custom UI SDK Integration in React Native App

For merchants who have built their app on a react native platform - Paytm provides a plugin for you to conveniently integrate Custom UI SDK for both Android and iOS. In this document, we will highlight the steps required to integrate Custom UI SDK with a native plugin for your app. This plugin helps you to build a seamless and responsive checkout experience for your iOS or Android application.

Pre-requisites

Before you begin the integration, make sure you follow the steps below:

  1. Create an account on Paytm as a merchant. Click how to create an account.

    Note: Save the MID and merchant key generated in the above step.
  2. The additional details such as Client Id and Client Secret Key will be shared with you over an email after the approval.

  3. Go through the checksum logic to understand how to generate and validate the checksum.

  4. Get the staging android or iOS Paytm app for integration testing on the merchant staging environment. For login into the staging Paytm app, use mobile no. 7777777770 and OTP 888888.

Integration steps for Paytm Custom UI SDK in React Native project

Add plugins to your react-native project.

  • npm install paytm-customuisdk-react-native --save 
  • react-native link paytm-customuisdk-react-native
  1. Open MainApplication.java class in an android directory of react native project.

    import com.paytm.PaytmCustomuisdkPackage;
  2. Then add new PaytmCustomuisdkPackage() to the list return in getPackages() method if not auto added after react-native link command in PackageList class.

    @Override
           protected List<ReactPackage> getPackages() {
             @SuppressWarnings("UnnecessaryLocalVariable")
             List<ReactPackage> packages = new PackageList(this).getPackages();
             // Packages that cannot be autolinked yet can be added manually here, for example:
             packages.add(new PaytmCustomuisdkPackage());
             return packages;
           }
  3. Append the following line to settings.gradle file.

    include ':paytm-customuisdk-react-native'
    project(':paytm-customuisdk-react-native').projectDir = new File(rootProject.projectDir, '../node_modules/paytm-customuisdk-react-native/android')
  4. Add the following lines in the dependencies section of your app’s build.gradle file.

    implementation project(':paytm-customuisdk-react-native');
  5. Add below maven URL in repositories of project android/build.gradle.

    allprojects {
       repositories {
           ...
           maven {
               url "https://artifactory.paytm.in/libs-release-local"
           }
       }
    }
  6. Enable multidex to use this sdk as given below in android/app/build.gradle.

    android {
      ...
     defaultConfig {
       ...
       multiDexEnabled true
     }
    }
    dependencies {
       ...
      implementation 'com.android.support:multidex:1.0.3'
    }
    
    Note: To help you with the integration, we have provided a sample merchant app integrated with this SDK. To get the sample app, please click here.
  1. Open Podfile and Update Platform Version.

    Navigate to the ios folder and open Podfile. You can do this using the following code.
     

    $ cd ios && open podfile.

  2.  Install Pods Using Cocoapods.

    Install pods after updating the iOS platform: pod install && cd ..

  3. Add the following in ios project.

    Open the projectName.workspace in ios folder.

    1. Open Info.plist : Add LSApplicationQueriesSchemes. Change its type to Array. Create a new item in it and set its value as "paytm".

    2. Go to Info tab -> URL Types: Add a new URL Type that you’ll be using as the callback from Paytm App (URL Scheme: "paytm"+"MID"). Example: paytmMid123.


    3. Open AppDelegate.m: Add following method before the end of the file ended by @end.

    4. Open AppDelegate.m and import LinkingManager to the top of the file which has delegate methods for implementing and handling URLScheme(response from Paytm invoke will be received here in this method. Which in turns notifies the Plugin.).

#import <React/RCTLinkingManager.h>
 
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  
  NSString *urlString = url.absoluteString;
  NSDictionary *userInfo =
  [NSDictionary dictionaryWithObject:urlString forKey:@"appInvokeNotificationKey"];
  [[NSNotificationCenter defaultCenter] postNotificationName:
   @"appInvokeNotification" object:nil userInfo:userInfo];
  return [RCTLinkingManager application:app openURL:url options:options];
}

XCode configurations

  1. In XCode, in the project navigator, right-click Libraries âžœ Add Files to [your project's name].

  2. Go to node_modules ➜ paytm-customuisdk-react-native and add PaytmCustomuisdk.xcodeproj.

  3. In XCode, in the project navigator, select your project. Add libRNPaytmCustomuiSdk.a to your project's Build Phases ➜ Link Binary With Libraries.

  4. Run your project (Cmd+R).

Note: To help you with the integration, we have provided a sample merchant app integrated with this SDK. To get the sample app, please click here.

Methods available in React Native SDK

  1. Now you can access SDK methods from ‘yourpageName’.js or .tsx file as below and Paytm consent checkbox view:
    import PaytmCustomuisdk, { PaytmConsentCheckBox,} from 'paytm-customuisdk-react-native';
     
    export default function HomePage{
     
    fetchAuthCode() {
       PaytmCustomuisdk.fetchAuthCode(clientId, mid)
           .then((res) => {
             setResult(JSON.stringify(res));
             setAuthCode(res.response);
           })
           .catch((err) => {
             setResult(err.message);
           });
     }
     
    return (
              <View style={{ padding: 8 }}>
                 <View>
                   <PaytmConsentCheckBox
                     onChange={(e: boolean) => setAuthCheck(e)}
                   />
                 </View>
                 <TextInput
                   style={styles.textInput}
                   defaultValue={clientId}
                   placeholder={'Client Id'}
                   onChangeText={(e) => setClientId(e)}
                 />
                 <View style={{ margin: 16 }}>
                   <Button title="Fetch" onPress={() => fetchAuthCode()} />
                 </View>
               </View>
     );
    }
  2. Implement the following methods to extract Paytm user’s saved instruments.
  1. isPaytmAppInstalledThis method is used to check whether Paytm is installed or not.
isPaytmAppInstalled

Method Usage:

PaytmCustomuisdk.isPaytmAppInstalled()

Response: Boolean

Parameter Description
True In case, Paytm App is installed and supports the feature to extract authcode
False In case, Paytm App is not there or does not support the feature to extract authcode
  1. fetchAuthCodeThis method is called to fetch authcode which shows consent checkbox dialog and only return authcode by pressing the ok button of dialog when the user checked the shown consent checkbox if Paytm app is installed.
fetchAuthCode

Method Usage:

PaytmCustomuisdk.fetchAuthCode(clientId, mid)

Method Parameters:

Attribute Description Mandatory

clientId

String

Unique Id given by Paytm app. Yes

mid

String

Unique Identifier given by Paytm app. Yes

Response:

 {"response" : authCode}
Attribute Description

authCode

String

Alphanumeric authCode string e.g. ‘Apfdf-2234-nhdjshj-wers’ in case auth code fetched
  1. You need to call the OAuth token API using the authorization code received to receive the refresh token and SSO token associated with the Paytm user.
    Note: SSO token will be used to fetch saved instruments of paytm user and refresh token will be used to get a new SSO token of paytm user after its expiry.
  1. 3
    After the user adds the product in the cart and clicks the button to proceed for checkout, your app calls the backend server to get the order payout. Then, your backend server calls Initiate Transaction API from the backend to generate the Transaction Token.

    Note: In case you wish to use the custom Callback URL in Initiate Transaction API then please include the config setMerchantCallbackUrl during Initialization of SDK.

  2. 4
    Using the transaction token received above, your backend server calls the Fetch Payment Options API to receive the different payment options including the user's saved instruments and other instruments like CC/DC, NB, UPI, EMI etc.

    Note: In case you do not want to create an order first, you may call the Fetch Payment Options API before Initiate Transaction. For more details please Get in touch with us.

  3. 5
    Call initPaytmSDK method

     

    You need to call initPaytmSDK method before calling any Transaction method. After calling the transaction method response will be in the “then” method in case of success and in “catch” method in case of error.

    Note: After any transaction method. It is necessary to call the initPaytmSDK method again.
    import PaytmCustomuisdk, { PaytmConsentCheckBox,} from 'paytm-customuisdk-react-native';
    
    export default function HomePage{
    
    initPaytmSdk() {
       PaytmCustomuisdk.initPaytmSDK(
         mid,
         orderId,
         txnToken,
         amount,
         isStaging,
         ''
       );
     }
     
    goForWalletTransaction() {
      PaytmCustomuisdk.goForWalletTransaction(paymentFlow)
         .then((res) => {
           showAlert(JSON.stringify(res), true);
         })
         .catch((err) => {
           showAlert(err.message, false);
         });
       }
    }

    Response from Transaction method:

    {
        "ORDERID": "PARCEL15816826759",
        "MID": "AliSub58582630351896",
        "TXNID": "20200214111212800110168052313701129",
        "TXNAMOUNT": "1.00",
        "PAYMENTMODE": "CC",
        "CURRENCY": "INR",
        "TXNDATE": "2020-02-14 17:48:13.0",
        "STATUS": "TXN_SUCCESS",
        "RESPCODE": "01",
        "RESPMSG": "Txn Success",
        "MERC_UNQ_REF": "test4",
        "UDF_1": "test1",
        "UDF_2": "test2",
        "UDF_3": "test3",
        "ADDITIONAL_INFO": "test5",
        "GATEWAYNAME": "ICICIPAY",
        "BANKTXNID": "68568621250",
        "BANKNAME": "HSBC",
        "PROMO_CAMP_ID": "PROMO CODE",
        "PROMO_RESPCODE": "702",
        "PROMO_STATUS": "FAILURE"
    }

    Method Usage:

    PaytmCustomuisdk.initPaytmSDK(
         mid,
         orderId,
         txnToken,
         amount,
         isStaging,
         ''
       );

    Method Parameters:

    Parameter Description Mandatory
    mid
    (string)
    Merchant id identifying a merchant Yes
    orderId
    (string)
    Unique identifier for current order Yes
    txnToken
    (string)
    Transaction token to identify the current transaction received in response to Initiate Transaction API from Paytm Yes
    amount
    (string)
    Order amount for the current transaction Yes
    isStaging
    (boolean)
    To set the staging environment Yes
    callbackUrl
    (string)
    Use this to define the custom CallbackUrl for receiving the result of the Transaction No
  4. 6
    Proceed for the transaction

    When the user clicks on the Pay button after entering the payment instrument’s details in the selected payment method, you need to proceed for the transaction. Please follow the steps below for proceeding with the transaction.

Invoke the goForWalletTransaction method to call Process Transaction API for wallet transaction.

Method Usage:

PaytmCustomuisdk.goForWalletTransaction(paymentFlow)

Method Parameters:

Attribute Description Mandatory

paymentFlow

String

current payment flow (NONE, ADDANDPAY) Yes

Invoke the method goForNewCardTransaction to call the Process Transaction API for new card transactions.


Method Usage:

PaytmCustomuisdk.goForNewCardTransaction(
     cardNumber,
     cardExpiry,
     cardCvv,
     cardType,
     paymentFlow,
     channelCode,
     issuingBankCode,
     '',
     authMode,
     saveCard
   )

Method Parameters:

Parameter Description Mandatory

cardNumber

String

card number digits for a new card Yes

cardExpiry

String

card expiry date in the format MM/YY (eg. 11/19) Yes

cardType

String

type of card (DEBIT_CARD, CREDIT_CARD) Yes

cardCvv

String

CVV of the card Yes

paymentFlow

String

current payment flow (NONE, HYBRID, ADDNPAY) Yes

authMode

String

the mode of 2FA chosen for the card (either by 'pin' or 'OTP'), options obtained from fetchBinDetails API Yes

channelCode

String

channel code of card obtained from fetchBinDetails API(eg. VISA, MASTER) Yes

bankCode

String

bank code of card obtained from fetchBinDetails API(eg. ICICI, AXIS) Yes

issuingBankCode

String

bank code of card obtained from fetchBinDetails API(eg. ICICI, AXIS) Yes

emiChannelId

String

EMI Plan id in case of an EMI transaction No

saveCard

Boolean

flag to indicate if  the new card should be saved at Paytm’s end Yes

Invoke the method goForSavedCardTransaction to call the Process Transaction API for saved card transactions.


Method Usage:

PaytmCustomuisdk.goForSavedCardTransaction(
     item.cardDetails.cardId,
     item.cardCvv,
     item.cardDetails.cardType,
     paymentFlow,
     item.channelCode,
     item.issuingBank,
     '',
     item.authModes[0]
   )

Method Parameters:

Parameter Description Mandatory

cardId

String

cardId for a saved card Yes

cardType

String

type of card (DEBIT_CARD, CREDIT_CARD) Yes

cardCvv

String

CVV of the card Yes

paymentFlow

String

current payment flow (NONE, HYBRID, ADDNPAY) Yes

authMode

String

the mode of 2FA chosen for the card (either by 'pin' or 'OTP'), options obtained from fetchBinDetails API Yes

channelCode

String

channel code of card obtained from fetchBinDetails API(eg. VISA, MASTER) Yes

issuingBankCode

String

bank code of card obtained from fetchBinDetails API(eg. ICICI, AXIS) Yes

emiChannelId

String

EMI Plan id in case of an EMI transaction No

Invoke the method goForNetBankingTransaction to call Process Transaction API for net banking transactions.

Method Usage:

PaytmCustomuisdk
     .goForNetBankingTransaction(netBankingCode, paymentFlow)

Method Parameters:

Parameter Description Mandatory

netbankingCode

String

bankCode for the bank Yes

paymentFlow

String

current payment flow (NONE, HYBRID, ADDNPAY) Yes

Invoke the goForUpiCollectTransaction method to call Process Transaction API for UPI collect transactions.

Method Usage:

PaytmCustomuisdk
     .goForUpiCollectTransaction(upiCode, paymentFlow, saveVPA)

Method Parameters:

Attribute Description Mandatory

paymentFlow

String

current payment flow (NONE, ADDANDPAY) Yes
upiCode
String
UPI handle for making payment(eg. xyz@paytm) Yes
saveVPA
String
To save method to the backend Yes
  1.  Call the method getUpiIntentList to get UPI intent appName list available for payment in user mobile.


    Method Usage:

    PaytmCustomuisdk.getUpiIntentList()

    Response:

    {"list":[{"appName":"Google Pay"}]}
    Attribute Description
    appName
    String
    Intent App Name
  2. Call the method goForUpiIntentTransaction to call Process Transaction API for UPI intent transactions. 


    Method Usage:

    PaytmCustomuisdk.goForUpiIntentTransaction(item.appName, paymentFlow)

    Method Parameters:

    Attribute Description Mandatory

    paymentFlow

    String

    current payment flow (NONE, ADDANDPAY) Yes
    appName
    String
    appName from the UPI intent list Yes
  1. Invoke the method goForUpiPushTransaction to call Process Transaction API for UPI push transactions.

    Method Usage:
    PaytmCustomuisdk
         .goForUpiPushTransaction(
           paymentFlow,
           bankAccountJson,
           vpaDetail.name,
           merchantDetails
         )
    Method Parameters:
    Attribute Description Mandatory

    paymentFlow

    String

    current payment flow (NONE, ADDANDPAY) Yes
    bankAccountJson
    Object
    Json object representing a bank account for UPI Yes
    vpaName
    String
    Virtual Payment Adress(eg.xyz@paytm) Yes
    merchantDetailsJson
    Object
    Json object containing merchant info for which payment is required Yes
  1. fetchUpiBalance: To fetch account balance for a UPI account after entering mpin. This method is required in case the merchant wants to integrate UPI Push flow through the SDK. Paytm App will be launched in this case.
fetchUpiBalance

 Method Usage:

PaytmCustomuisdk
     .fetchUpiBalance(bankAccountJson, vpaDetail.name)

Method Parameters:

Attribute Description Mandatory
bankAccountJson
Object
Json object representing a bank account for UPI Yes
vpaName
String
Virtual Payment Adress(eg.xyz@paytm) Yes
  1. setUpiMpin: This method is used to set MPIN for a UPI account. Paytm app will be launched in this case.
setUpiMpin

 Method Usage:

PaytmCustomuisdk
     .setUpiMpin(bankAccountJson, vpaDetail.name)

Method Parameters:

Attribute Description Mandatory
bankAccountJson
Object
Json object representing a bank account for UPI Yes
vpaName
String
Virtual Payment Adress(eg.xyz@paytm) Yes
  1. 7
    Integration of Additional/Optional Methods
  1. openPaytmAppForAddMoneyToWallet: This method can be used to invoke and complete the transaction from Paytm App.
openPaytmAppForAddMoneyToWallet

Method Usage:

PaytmCustomuisdk.openPaytmAppForAddMoneyToWallet()

Sample Response:

{
  "ORDERID": "PARCEL16105282330",
  "MID": "AliSub585826303xx8xx",
  "TXNID": "202101131112128001101688774748xxxxxx",
  "TXNAMOUNT": "1.00",
  "PAYMENTMODE": "PPI",
  "CURRENCY": "INR",
  "TXNDATE": "2021-01-13 14:27:12.0",
  "STATUS": "TXN_SUCCESS",
  "RESPCODE": "01",
  "RESPMSG": "Txn Success",
  "MERC_UNQ_REF": "test4",
  "UDF_1": "test1",
  "UDF_2": "test2",
  "UDF_3": "test3",
  "ADDITIONAL_INFO": "test5",
  "GATEWAYNAME": "WALLET",
  "BANKTXNID": "151096542207",
  "BANKNAME": "WALLET"
}
  1. getBin: Get Bin can be used to get the bin information and success rate of the entered card. It can be used with a Transaction token or Access token.
getBin

Note: Call this method after the initPaytmSDK method in case tokenType is TXN_TOKEN.

 Method Usage:

PaytmCustomuisdk
     .getBin(this.cardNumber, tokenType, this.txnToken, this.mid, null)

Method Parameters:

Parameter Description Mandatory

cardSixDigit

String

First six digits of the card Yes

tokenType

String

It can be "TXN_TOKEN","ACCESS" Yes

token

String

Token value used(access/txntoken) Yes

mid

String

Merchant ID Yes

referenceID

String

Unique ID between 10 to 20 digits and is only required in case of tokenType as ACCESS. It should be similar to the value used in access token generation. If token type is ACCESS

Response:

{
    "head": {
        "requestId": "null",
        "responseTimestamp": "1630415256947",
        "version": "v1"
    },
    "body": {
        "authModes": ["otp"],
        "binDetail": {
            "bin": "541919",
            "binTokenization": "false",
            "channelCode": "MASTER",
            "channelName": "MASTER",
            "cnMax": "16",
            "cnMin": "16",
            "cvvL": "3",
            "cvvR": "true",
            "expR": "true",
            "isActive": "true",
            "isIndian": "true",
            "issuingBank": "HDFC Bank",
            "issuingBankCode": "HDFC",
            "paymentMode": "DEBIT_CARD"
        },
        "errorMessage": "EMI not available",
        "hasLowSuccessRate": {
            "msg": "",
            "status": "false"
        },
        "iconUrl": "https://staticgw3.paytmpayments.com/33.1.1/images/wap/merchantLow/master.png",
        "isEmiAvailable": false,
        "isHybridDisabled": false,
        "oneClickMaxAmount": "2000",
        "oneClickSupported": false,
        "prepaidCard": false,
        "prepaidCardMaxAmount": "100000",
        "resultInfo": {
            "resultCode": "0000",
            "resultMsg": "Success",
            "resultStatus": "S"
        }
    }
}
  1. fetchNBList: FetchNBList can be used to get the list of all netbanking banks along with their success rate. This method can be used with a transaction or access token.
fetchNBList

Note: Call this method after the initPaytmSDK method in case tokenType is TXN_TOKEN.

Method Usage:

PaytmCustomuisdk
     .fetchNBList(tokenType, this.txnToken, this.mid, this.orderId, null)

Method Parameters:

Parameter Description Mandatory

orderID

String

Unique identifier for current order If tokenType is TXN_TOKEN

tokenType

String

It can be "TXN_TOKEN","ACCESS" Yes

token

String

Token value used(access/txntoken) Yes

mid

String

Merchant ID Yes

referenceID

String

Unique ID between 10 to 20 digits and is only required in case of tokenType as ACCESS. It should be similar to the value used in access token generation. If token type is ACCESS

Response:

{
    "head":{
        "requestId":null,
        "responseTimestamp":"1591622928848",
        "version":"v1"
    },
    "body":{
        "extraParamsMap":null,
        "resultInfo":{
            "resultStatus":"S",
            "resultCode":"0000",
            "resultMsg":"Success"
        },
        "nbPayOption":{
            "displayName":"Net Banking",
            "isDisabled":{
                "status":"false",
                "msg":""
            },
            "payChannelOptions":[
                {
                "isDisabled":{
                    "status":"false",
                    "msg":null
                },
                "hasLowSuccess":{
                    "status":"false",
                    "msg":""
                },
                "iconUrl":"AXIS.png",
                "isHybridDisabled":false,
                "channelCode":"AXIS",
                "channelName":"Axis Bank"
                },
                {
                "isDisabled":{
                    "status":"false",
                    "msg":null
                },
                "hasLowSuccess":{
                    "status":"false",
                    "msg":""
                },
                "iconUrl":"HDFC.png",
                "isHybridDisabled":false,
                "channelCode":"HDFC",
                "channelName":"HDFC Bank"
                }
            ]
        }
    }
}
Parameter Description

channelName

Bank Name

channelCode

Bank Code

iconUrl

Bank Logo URL

hasLowSuccess

Information about bank’s success rate (HasLowSuccess contains Boolean status and String msg )

  1. fetchEmiDetails  (For Android Only): This method is used to fetch available EMI plans on a given card.
fetchEmiDetails

Method Usage:

PaytmCustomuisdk
     .fetchEmiDetails(cardType, channelCode)

Method Parameters:

Parameter Description Mandatory

channelCode

String

channelCode of card obtained from fetchBinDetails API(eg. VISA, MASTER) Yes

cardType

String

type of card (DEBIT_CARD, CREDIT_CARD) Yes
  1. getLastNBSavedBank: This method is used to fetch the bank code through which the last successful Netbanking transaction was done.
getLastNBSavedBank

Method Usage:

PaytmCustomuisdk
     .getLastNBSavedBank()

Response:

This method will return a string parameter.

Value Description
"ICICI" If a user has used ICICI bank in his last net banking transaction
  1. getLastSavedVPA: This method is used to fetch the VPA through which the last UPI Collect transaction was done by the user.
getLastSavedVPA

Method Usage:

PaytmCustomuisdk.getLastSavedVPA()

Response:

This method will return a string parameter.

Value Description
"abc@xyz" If a user has used this VPA in his last UPI collect transaction
  1. isAuthCodeValid (For Android Only): This method is used to check if the fetched authcode is valid or not.
isAuthCodeValid

Method Usage:

PaytmCustomuisdk
     .isAuthCodeValid(clientId, authCode)

Method Parameters:

Parameter Description Mandatory

clientId

String

The clientId issued from Paytm identifying a merchant Yes

authCode

String

authcode got from fetchAuthCode method Yes

Response: Boolean

Parameter Description
True In case, auth code is valid which was fetched from fetchAuthCode method.
False In case, auth code is not valid which was fetched from fetchAuthCode method.
  1. checkHasInstrument (For Android Only): This method is called to check if the user has any saved instruments.
checkHasInstrument

 Method Usage:

PaytmCustomuisdk
     .checkHasInstrument(mid)

Method Parameters:

Parameter Description Mandatory

mid

String

Merchant id identifying a merchant Yes

Response: Boolean

Parameter Description
True In case, Paytm app is installed and the merchant has payment instrument
False In case, Paytm app is not installed or merchant doesn’t have any payment instrument
  1. setEnvironmentThis method is used to change the PG environment from production to staging.
setEnvironment

 Method Usage:

PaytmCustomuisdk.setEnvironment(environment)

Method Parameters:

Attribute Description Mandatory

environment

String

Current environment (STAGING / PRODUCTION) Yes
  1. getEnvironment: This method is called to check the current environment.
getEnvironment

 Method Usage:

PaytmCustomuisdk.getEnvironment()
  1. PaytmConsentCheckbox: This method is used to customize the consent checkbox as per your theme and requirement.
PaytmConsentCheckbox

View Properties:

Properties Description

tintColor

object

  • true - when checkbox is selected for color

  • false - when checkbox is unselected for color

style

object

  • fontFamily - use font exact font name as in your assets/fonts directory.
    For example: fonts/Entypo-Bold.ttf => fontFamily : "Entypo-Bold"
  • color - to set text color
  • backgroundColor - color to set background color
  • fontSize - to set text size 

Use the properties as below:

<PaytmConsentCheckBox
    tintColor ={
        {
            true: "blue", 
            false:"black"
        }
    }
    style ={
      {
        fontFamily:     "Entypo", 
        fontSize:       "18", 
        backgroundColor:"white", 
        padding:        "24", 
        color:          "black"
      }
    }     
   onChange={(e: boolean)=>setCheck(e)}
 />