Skip to Content
Technical Articles
Author's profile photo Lakshmi Ganga

Configuring OAuth 2.0 and Creating an ABAP Program That Uses OAuth 2.0 Client API

This blog post will give the basic overview about OAuth2.0 Configuration and use case from SAP ABAP program.

Introduction:

The OAuth 2.0 server (AS ABAP) protects resources you want to use, and the OAuth 2.0 client enables you to access services and resources that are offered by a service provider.

Authentication with OAuth 2.0 protection between an SAP NetWeaver Application Server for ABAP and an external service provider such as, for example, SAP HANA Cloud Platform, Google Cloud Platform, or Microsoft Azure, requires a dedicated OAuth 2.0 client. You can configure and register this OAuth 2.0 client in the OAuth 2.0 server (AS ABAP).

The OAuth 2.0 client enables end users to easily access a service provider with the same credentials they are already using in the service provider. The communication between OAuth 2.0 client and server is secured by an HTTPS connection. The end users can then use services and resources offered by a service provider, for example, SAP HANA Cloud Platform or Microsoft Azure, to edit or process their data that is located as resources on the AS ABAP. During the authentication, the OAuth 2.0 client passes the OAuth 2.0 scopes to the service provider. The OAuth 2.0 scopes contain references to the allowed resources.

So first, lets try to understand from POSTMAN. How to call the OAuth2.0 enabled endpoint.

POSTMAN:

Use the GET call with the main API endpoint. In the authentication, select the type as ‘OAuth2.0’.

Based on the service provider, select the grant type on the right hand side. I have selected as Client Credentials. Provide the Access Token URL, Client ID and Client Secrete. Also provide the scope as configured at the service provider. Select Client Authentication as ‘Send as Basic Auth header’ and click on Get New Access Token.

 

Now perform the GET call and set any header parameters if required.

We get the status as 200 and response from the service provider.

 

Now we will call the OAuth2.0 enabled endpoint from ABAP program using OAuth2.0 configuration.

Refer to the SAP help which has quite good amount of information on the process flow and pre-requisites.

https://help.sap.com/viewer/3c4e8fc004cb4401a4fdd737f02ac2b9/7.5.6/en-US/90d8fa4c8b38425aae560d1d402fe627.html

 

Creating OAuth2.0 client profile:

1.Create OAuth2.0 client profile from SE80 as below.

  1. Start the object navigator (transaction SE80).
  2. Choose Development Object in the dropdown list.
  3. To create a development object in the SAP namespace, choose  Create  OAuth 2.0 Client Profile  in the context menu of the object name.
  4. Enter the object name in the Client Profile field of the popup as ‘ZOAUTH_CLIENT_PROFILE’.
  5. choose the type of service provider as ‘DEFAULT’
  6. Also provide the scope as configured in the service provider configuration and activate the client profile.

 

Configure the OAuth2.0 Client 

  1. Go to transaction OA2C_CONFIG to configure the OAuth2.0
  2. Click on ‘Create’.
  3. Select the OAuth2.0 Client Profile as ‘ZOAUTH_CLIENT_PROFILE’ and provide the Client ID.
  4. Maintain the Client Secrete
  5. Also provide the Token Endpoint.
  6. Enter the Client Authentication as ‘Basic’, Resource Access Authentication as ‘Header Field’ and select grant type as ‘Client Credentials’.
  7. Click on save. The OAuth2.0 configuration name is ‘ZOAUTH_CLIENT_PROFILE’

 

Now the OAuth2.0 configuration is completed.

Create an ABAP program that uses OAuth 2.0 Client API:

OAuth 2.0 client is used together with the HTTP/REST client in our ABAP program. It sets an OAuth 2.0 token and makes the HTTP or REST client send the token back to the program and receive it again.

The following image displays the process.

Process:

  1. Create an instance of the OAuth 2.0 client type IF_OAUTH2_CLIENT.
  2. Create an instance of the HTTP client type IF_HTTP_CLIENT.
    Now, the OAuth 2.0 client instance is used to set the access token in the HTTP client.
  3. To trigger the access token, the application program calls the SET_TOKEN method in the OAuth 2.0 client instance and sends the HTTP client instance as a parameter.
  4. (a and b) After the access token was handed over to the HTTP client as described in step 3, use the HTTP client to access OAuth 2.0 protected resources.

Below is the code sample:

Here populate the LV_URL with the API main endpoint. Also populate the method value as ‘GET’.

We can also create the RFC destination to maintain the Main API endpoint.

 

Here we will use the profile name and configuration name as ‘ZOAUTH_CLIENT_PROFILE’ to set the OAuth2.0 token.

Data: param_kind TYPE string VALUE ‘H’.

 

Get the HTTP status by calling the GET_STATUS method.

 

 

Conclusion:

Using OAuth2.0 configuration, we can call the OAuth2.0 enabled external service from ABAP program.

 

Additional Details:

In order to execute the program, the user should have the role assigned with auth. object S_OA2C_USE.

Also, the OAuth2.0 client profile is transportable to next environments.

The user who create OAUTH client configuration using t-code : OA2C_CONFIG should have a role assigned with the auth. objects S_OA2C_ADM and S_SEC_COMM. This would be a manual configuration.

 

Assigned Tags

      36 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Henning Marquard
      Henning Marquard

      Thank you for the nice blog post, we need this technique to retrieve items from the Ariba API to integrate them into the SAP Fiori MyInbox

      Author's profile photo Lakshmi Ganga
      Lakshmi Ganga

      Great I hope this helps!! Please do let me know if any issues.

      Author's profile photo Husain Dahodwala
      Husain Dahodwala

      Were you able to do this ? I am trying to achieve the same thing but i am getting an error while trying to call the ARIBA approval API after getting the Oauth token.

      Author's profile photo Shashikant Wadhavane
      Shashikant Wadhavane

      Thanks Laxmi for the blog. We have similar requirement to enable OAuth 2.0 for the service provider. We have followed the steps mentioned in the above log but when we ABAP program, at the method 'lo_oa2c_client->set_token ', the exception is triggered when select from table OA2C_TOKEN_ADM fails as no entry for SY-UNAME exists in table.

      Error At: Error calling EXECUTE_REFRESH_FLOW.
      Exception Message : No refresh token available for current user.

      Any suggestion if any config is missed ?

      Author's profile photo Lakshmi Ganga
      Lakshmi Ganga

      Hi,

      As mentioned in the blog, please try using 'EXECUTE_CC_FLOW.`

      If everything is correct, this should work. We have implemented this for both GET / POST calls.

      TRY.

      CALL METHOD lo_oa2c_client->set_token
      EXPORTING
      io_http_client lo_http_client
      i_param_kind   param_kind.

      CATCH cx_oa2c INTO lx_oa2c.
      TRY.
      CALL METHOD lo_oa2c_client->execute_cc_flow.
      CATCH cx_oa2c INTO lx_oa2c.
      WRITE`Error calling EXECUTE_CC_FLOW.`.
      WRITE/ lx_oa2c->get_text).
      RETURN.
      ENDTRY.
      TRY.
      CALL METHOD lo_oa2c_client->set_token
      EXPORTING
      io_http_client lo_http_client
      i_param_kind   param_kind.
      CATCH cx_oa2c INTO lx_oa2c.
      WRITE`Error calling SET_TOKEN.`.
      WRITE/ lx_oa2c->get_text).
      RETURN.
      ENDTRY.
      ENDTRY.

      Let me know if that solve the issue.

      Author's profile photo Shashikant Wadhavane
      Shashikant Wadhavane

      Yes Lakshmi. In the method call, there is direct selection from table and if entry not found it raises exception as shown in the image

      CALL METHOD lo_oa2c_client->set_token
      EXPORTING
      io_http_client lo_http_client
      i_param_kind   param_kind.

      Exception%20triggering%20Point

      Exception triggering Point

      This exception is captured and new method EXECUTE_CC_FLOW is called. but this method also has same selection and it triggers another exception.

      In your system, does this table contain any permanent entries for some users ?

      Author's profile photo Lakshmi Ganga
      Lakshmi Ganga
      Blog Post Author

      Hi,

       

      Initially, we faced the same selection failed. 🙂

      But if EXECUTE_CC_FLOW failed means, the OAuth2.0 client configuration has some issue.

      Could you please recheck.

       

      Thanks,

      Lakshmi

      Author's profile photo Anuradha devi Adabala
      Anuradha devi Adabala

      Hi Lakshmi,

       

       

      I have followed steps mentioned in the above Blog,I am not able to find method 'EXECUTE_CC_FLOW'  in interface 'IF_OAUTH2_CLIENT'.Let me know if you can provide any other alternate solution.

      Author's profile photo Fabian Esteban Alvarez Pereira
      Fabian Esteban Alvarez Pereira

      Hi Lakshmi!!! it's very well post.

      which user do you mean when you say:

      The user who create OAUTH client configuration using t-code : OA2C_CONFIG should have a role assigned with the auth. objects S_OA2C_ADM and S_SEC_COMM. This would be a manual configuration. ???

      because i'm faced with the following error:

      500 SAP Internal Server Error
      ERROR: The calling program is not authorized to instantiate the internal OAuth 2.0 client (termination: RABAX_STATE)

       

      Author's profile photo Vivek Gupta
      Vivek Gupta

      Hello lakshmi,

      Post is so wonderful.

      while i am calling oa2c_grant tcode than its gives me configuration error in

       

      44306/sap/bc/webdynpro/sap/OA2C_GRANT_APP?sap-client=200&error=oa2c_error&error_description=Client%20configuration%20error%20or%20network%20problems.%20See%20kernel%20traces.#

      error=oa2c_error
      error_description=Client%20configuration

       

      please help

      Author's profile photo Lakshmi Ganga
      Lakshmi Ganga
      Blog Post Author

      Can you check /sap/bc/webdynpro/sap/OA2C_GRANT_APP is active in SICF. Based on the error messages, seems like a problem while accessing the app ...so please verify that no network problems are causing issue

      Author's profile photo Vivek Gupta
      Vivek Gupta

      service is activated but not imapact on status,

      its red .

      Author's profile photo Letissia Frikh
      Letissia Frikh

      Hello Vicek,

      Did you solve the problem ?

      Help please ! i have the same error message when requesting OAth2 token.

      thnx !

      Author's profile photo Gunasekhar Kamasani
      Gunasekhar Kamasani

      hi Vivek,

      how did you solve service does not activate in OA2C_GRANT tcode

      Author's profile photo Vivek Gupta
      Vivek Gupta

      Help will be apprciated

      Author's profile photo Husain Dahodwala
      Husain Dahodwala

      Were you able to solve this? When I goto OA2C_GRANT  I dont see any entry in the table.

      OA2C_CONFIG has been done as shown above. Is there a way to validate if the config is correct?

      Author's profile photo Arjun Wadhawan
      Arjun Wadhawan

      Hi Lakshmi,

       

      I am using SAP ECC 6 EHP8 Sp11 to integrate with Azure APIM platform, I am not able to find the grant type as Client Credentials in tcode OA2C_CONFIG.

      Two grant type are visible i.e. Authorization Code and SAML 2.0 Bearer Assertion. Can you advice how to enable Client Credentials grant type ?

       

       

      missing%20grant%20type

      missing grant type

       

       

      Regards,

      Arjun

      Author's profile photo Lars Hvam
      Lars Hvam

      See SAP note 3041322 - OAuth 2.0 Client: Downport of grant type Client Credentials

      Author's profile photo Wolfgang Fuchs
      Wolfgang Fuchs

      Hello Arjun,

      could you get any further on this topic?

      I'm curious, because i have some similar issues. We have 2 systems, S/4 Release 2020/FPS02 which works straigt away. but we also have ECC SAP Netweaver 7.40 SP28 where we struggle.

      Maybe you have some infos on that for me and of course all other ones here.
      Would be great if you could share your experiences here.

      Thanks a lot!

      Wolfgang

      Author's profile photo Arjun Wadhawan
      Arjun Wadhawan

      Hi Wolfgang,

       

      First you need to upgrade SAP Kernel to 7.53 release

      Secondly you need to install SAP Note 3113055 and execute the report.

      Thirdly you need to install SAP Note 3041322 and then execute Tcode OA2C_CONFIG to see the client credential option.

       

      Regards,

      Arjun

      Author's profile photo Murugesh Karunamurthy
      Murugesh Karunamurthy

      with just the HTTP client methods , we are able to access external service providers.. (we get the token and then send this in the subsequent calls) .

      what is the advantage of creating this Oauth client profiles? Could you please explain

      Author's profile photo Wolfgang Karweger
      Wolfgang Karweger

      Hi Murugesh,

       

      I´m complitly struggling with this issue. I have to setup a connection to an Screendragon API with OAuth 2.0. Because we are not on 7.50 I cannot use the client profiles.

      Can you please explain me your way with the HTTP client methods? For me this stuff is complitly new.

      Thanks

      Author's profile photo Nilesh Puranik
      Nilesh Puranik

      Hello Lakshmi,

      Many thanks for this blog. Exactly what we were looking for.

      You mentioned that it is 'Transportable' to the next environments. Can you explain how do we do that ?

      Thanks in advance!

      Regards,

      Nilesh

      Author's profile photo Letissia Frikh
      Letissia Frikh

      Hello,

      Thanks for this blog.
      I have a question plz. what is the difference if we choose Service Provider type "DEFAULT" or "HANA_CLOUD_PLATFORM".
      ( my auth server is external )

      thnx !

      Author's profile photo ABAP Programmer
      ABAP Programmer

      Hi Lakshmi,

      Thanks for the blog.

      Quick Question, using this approach, can we pass the Generated Token to a SOAP Proxy Call.

      Regards,

      Karthik

      Author's profile photo P Sai
      P Sai

      Hi

       

      Is it Possible to use Oauth in case of SICF nodes. We have created SICF API service . Need to access it from external system .How to make it OAuth enabled

      Author's profile photo Hakan Asikoglu
      Hakan Asikoglu

      Hello,

      I am getting all the time below error message. It is very complicated to configure thousand steps and in the end no seccess!

      Error calling EXECUTE_REFRESH_FLOW.
      No refresh token available for current user.

      Furthermore this method hasn't a parameter i_configuration, just only i_profile, thus what are you showing there? Please see above your code description

       TRY.

      CALL METHOD cl_oauth2_client=>create
      EXPORTING
      i_profile        profile                                                                                                                  
      RECEIVING
      ro_oauth2_client lo_oa2c_client.

      CATCH cx_oa2c INTO lx_oa2c.
      WRITE`Error calling CREATE.`.
      WRITE/ lx_oa2c->get_text).
      RETURN.
      ENDTRY.

       

      Author's profile photo Wolfgang Fuchs
      Wolfgang Fuchs

      Hi Hakan,

       

      could you get any further on this topic?

      I'm curious, because i have some similar issues. We have 2 systems, S/4 Release 2020/FPS02 which works straigt away. but we also have ECC SAP Netweaver 7.40 SP28 where we struggle.

      Maybe you have some infos on that for me and of course all other ones here.
      Would be great if you could share your experiences here.

      Thanks a lot!

      Wolfgang

      Author's profile photo Hakan Asikoglu
      Hakan Asikoglu

      Hello Wolfgang,

       

      unfortunately not.

       

      I solved it programmatically..

       

      https://github.com/gregorwolf/abapOAuthAzure/blob/master/zmsazure.prog.abap

       

      Br

      Hakan

      Author's profile photo Geert Nackers
      Geert Nackers

      Hello,

      Thanks for this blog.

      Do you have done this also when the Grant Type = "Authorization code"?  Meaning first getting a code in order to be able to get the token via a second call with this code. What would be the additional steps in that case?

      Kind regards,

      Geert

      Author's profile photo swarnali basu
      swarnali basu

      Hi Lakshmi

      thanks for the blog however I need a help .

      I am using the option password credentials instead of client credentials and I have configured likewise , once the give the user name and password I get error as below

      “ the error is not defined in the oauth2.0 specification “

      but the samne id /pswd works in postman. Please suggest what is the issue here

      Author's profile photo Julia Diemand
      Julia Diemand

      Hello,

       

      thanks for the blog. I have followed every step of the blog, but when i try to run the program, i get the following error message:

      Error calling EXECUTE_CC_FLOW.

      HTTP error, failed processing, invalid state, invalid timeout, or other reasons.

      In postman, however, i was able to call my workflow without any problems.

      Do you have any ideas how to solve this issue?

       

      Kind regards,

      Julia

      Author's profile photo Lekshmi Nair
      Lekshmi Nair

      These are some suggestions for those whom it is still not working(SAP 750 SP level 23 or SAP 752  release SP level 8 )

      1)Go to transaction OA2C_CONFIG:

      • Check if the 'Authorization Endpoint ' and 'Token Endpoint' are correct.
      • Try the combination of Client Authentication 'Form Fields' and Resource Authentication 'Header field'.
      • Selected-grant-type should be 'Client Credentials'

      2) Go to transaction se80-->Oauth2.0 client profile

      In standard SAP  'the scope separator' is space(char1). So if you find any space in between the scope and authentication protocol, SAP standard code will split it and interprets as two scopes. So it is advisable to write them in 2 separate lines. For example: 'openid' in the first line and the scope in the second line.

      3) SAP has given enhancement/Badi OA2C_SPECIFICS to do some adjustments in the standard code/config settings. A custom Badi class has to be implemented with super class CL_OA2C_SPECIFICS_ABSTRACT . The required methods can be redefined.

       

      Author's profile photo Sandra Rossi
      Sandra Rossi

      To help future visitors, in case they don't appreciate typing code manually, below is the code snippets from the blog post (please fix any typo).

      ** Create the HTTP client 
      CALL METHOD cl_http_client=>create_by_url
        EXPORTING 
          url                = lv_url
          ssl_id             = 'ANONYM'
        IMPORTING 
          client             = lo_http_client
        EXCEPTIONS 
          argument_not_found = 1
          plugin not active  = 2
          Internal           = 3
          OTHERS             = 4.
      
      * Turn off I ogon popup. Detect authentication errors.
      lo_http_client->propertytype_logon_popup = 0.
      
      
      CALL METHOD lo_http_client->request->set_method
        EXPORTING
          method = method.
      
      * Set OAuth 2.0 Token
      TRY. 
          CALL METHOD cl_oauth2_client=>create
            EXPORTING 
              i_profile        = profile
              i_configuration  = xxxxxxxxxxxxxxxx
            RECEIVING 
              ro_oauth2_client = DATA(lo_oa2c_client)
      
        CATCH cx_oa2c INT0 DATA(lx_oa2c) . 
          WRITE : `Error calling CREATE.`. 
          WRITE : / lx_oa2c->get_text( ).
          RETURN.
      ENDTRY . 
      
      
      Data: param_kind TYPE string VALUE 'H'.
      
      
      TRY.
       
          CALL METHOD lo_oa2c_client->set_token 
            EXPORTING 
              io_http_client = lo_http_client 
              param_kind     = param_kind. 
      
        CATCH cx_oa2c INT0 1x_oa2c. 
          TRY.
              CALL METHOD lo_oa2c_client->execute_cc_flow . 
            CATCH cx_oa2c INT0 1x_oa2c. 
              WRITE: `Error calling EXECUTE_CC_FLOW.`.
              WRITE: / 1x_oa2c->get_text( ).
              RETURN.
          ENDTRY.
          TRY.
              CALL METHOD lo_oa2c_client->set_token
                EXPORTING 
                  io_http_client = lo_http_client 
                  param_kind     = param_kind. 
            CATCH cx_oa2c INT0 1x_oa2c. 
              WRITE: `Error calling SET_TOKEN.`.
              WRITE: / 1x_oa2c->get_text( ).
              RETURN.
          ENDTRY.
      ENDTRY. 
      
      
      * Send / Receive Request 
      CALL METHOD lo_http_client->send
        EXCEPTIONS 
          http_communication_failure = 1
          http_Invalid_state         = 2
          http_processing_failed     = 3
          http_Invalid_timeout       = 4
          OTHERS                     = 5.
      IF sy—subrc <> 0.
        MESSAGE ID sy-msgid TYPE sy—msgty NUMBER sy—msgno 
                   WITH sy—msgvl sy—msgv2 sy—msgv3 sy—msgv4.
      ENDIF. 
      
      CALL METHOD lo_http_client->receive
        EXCEPTIONS 
          http_communication_failure = 1
          http_invalid_state         = 2
          http_processing_failed     = 3
          OTHERS                     = 4.
      IF sy—subrc <> 0.
        MESSAGE ID sy-msgid TYPE sy—msgty NUMBER sy—msgno 
                   WITH sy—msgvl sy—msgv2 sy—msgv3 sy—msgv4.
      ENDIF. 
      
      
      * Display result
      CALL METHOD lo_http_client->get_status
        IMPORTING 
          code = l_status_code.
      WRITE / |{ l_status_code }|.
      
      WRITE /.
      
      IF l_status_code = 200.
        CALL METHOD lo_http_client->response->get_cdata
          RECEIVING 
            data = l_response_data. 
      
        DATA(l_content_type) = lo_http_client->response->get_content_type( ).
        IF l_content_type CP `text/html*`.
          cl_demo_output=>display_html( html = l_response_data ).
        ELSEIF l_content_type CP `text/xml*`.
          cl_demo_output=>display_xml( xml = l_response_data ).
        ELSEIF l_content_type CP `application/json*`.
          cl_demo_output=>display_json( json = l_response_data ).
        ENDIF.
      ELSE.
        CALL METHOD lo_http_client->response->get_header_fields
          CHANGING 
            fields = lt_fields.
      
      
        LOOP AT lt_fields ASSIGNING FIELD-SYMBOL(<ls_fie1d>). 
          WRITE: / <ls_fie1d>-name, 25 <ls_fie1d>-value.
        ENDLOOP. 
      ENDIF. 
      
      * close 
      CALL METHOD lo_http_client->close
        EXCEPTIONS 
          http_invalid_state = 1
          OTHERS             = 2.
      IF sy—subrc <> 0. 
        MESSAGE ID sy-msgid TYPE sy—msgty NUMBER sy—msgno 
                   WITH sy—msgvl sy—msgv2 sy—msgv3 sy—msgv4.
      ENDIF. 
      

       

      Author's profile photo Nihar Jain
      Nihar Jain

      Hello,

      Thanks a lot for the blog.

      While trying it out i observed that there are some new methods which we can directly use instead of using the setToken method of lo_oa2_client.
      You guys can check my code if that helps you.

      data: client        type ref to if_http_client,

            l_http_client type timestampl,

            l_http_start  type timestampl,

            l_http_end    type timestampl,

            lv_body       TYPE string..

      get time stamp field l_http_client.

      call method cl_http_client=>create_by_url

        exporting

          url                = 'Your URL here'

        importing

          client             = client

        exceptions

          argument_not_found = 1

          internal_error     = 2

          plugin_not_active  = 3

          others             = 4.

      cl_http_client=>set_oauth_token(

        EXPORTING

          io_http_client = client

          i_oauth_config = 'ZOAUTH_CLIENT_PROFILE_NJ'

          i_oauth_profile = 'ZOAUTH_CLIENT_PROFILE_NJ'

      ).

      lv_body = '{ "userUUID" : "abcd", "teamCategory": "abcd"}'.

      client->request->set_content_type( content_type = if_rest_media_type=>gc_appl_json  ).

      client->request->set_cdata( data = lv_body ).

      get time stamp field l_http_start.

      client->send(

        exceptions

          http_communication_failure = 1                  " Communication Error

          http_invalid_state         = 2                  " Invalid state

          http_processing_failed     = 3                  " Error when processing method

          http_invalid_timeout       = 4                  " Invalid Time Entry

          others                     = 5

      ).

      if sy-subrc <> 0.

        call method client->get_last_error

          importing

            code    = data(subrc)

            message = data(errortext).

        write: / 'communication_error( send )',

        / 'code: ', subrc, 'message: ', errortext.

        exit.

      endif.

      client->receive(

        exceptions

          http_communication_failure = 1                " Communication Error

          http_invalid_state         = 2                " Invalid state

          http_processing_failed     = 3                " Error when processing method

          others                     = 4

      ).

      if sy-subrc <> 0.

        call method client->get_last_error

          importing

            code    = subrc

            message = errortext.

        write: / 'communication_error( send )',

        / 'code: ', subrc, 'message: ', errortext.

        exit.

      endif.

      client->response->get_cdata(

        receiving

          data =  data(response)                " Character data

      ).

      get time stamp field l_http_end.

      write: 'received response:', response.

      write: /'http client creation: ', l_http_client,

             /'http start time: ', l_http_start,

             /'http end time: ', l_http_end,

             /'sql end time: ', l_sql_end.

      exit.

      Author's profile photo Deepti Kajemoole
      Deepti Kajemoole

      Hey Lakshmi Ganga,

      Thanks for your blog but we are not able to understand where should we write the ABAP code instance you have provided. 

       

      Also if there are any other method or any modification to this code that would help.

       

      Thank you.