 | Level: Intermediate Steve Fang, Software Developer , IBM Toronto Laboratory John Green, Advisory Staff Member , IBM Toronto Laboratory Richard Gregory, Software Developer , IBM Toronto Laboratory
07 Mar 2002 This article is the first one in a three-part series that shows how to transform existing CICS External Presentation Interface (EPI) applications into enterprise services using the 3270 terminal service development tools that are part of the Enterprise Services Toolkit in WebSphere Studio Application Developer Integration Edition.
© Copyright International Business Machines Corporation 2002. All rights reserved.
Introduction
This article is the first of a three-part series that shows how to transform existing CICS#xae External Presentation Interface (EPI) applications into enterprise services using the 3270 terminal service development tools that are part of the Enterprise Services Toolkit in IBMTM WebSphereTM Studio Application Developer Integration Edition (hereafter called Application Developer). This article provides a step-by-step exercise that demonstrates how enterprise services can be quickly created from the CICS EPI IVP Menu application. The exercise shows you how to import 3270 EPI screens, define a new service in terms of the relationships between screens, create this new service, and write a sample application that uses the new service. In addition to the example, this article explains Application Developer tooling functionality and provides hints and tips to help you move from the example to working with real applications.
Creating an enterprise service from an EPI application involves these steps:
-
Import the 3270 screens. The screens will be used to create XSD types that will be used to pass data into, through, and out of the service implementation. This will be covered below under
Setting up to create the service definition
.
- Record a dialog. A recording of the possible screen navigations, which is stored as a WSDL document, is used to define the operations that are part of the new service.
- Optionally, compose other services using the new service. The service we create may be a building block for a more complex service; the service definition may be used within a flow, as we will see in Part 2 of this series.
- Generate client and server code to be able to use the service. The XSD types are turned into Java helper classes and the WSDL document is used to create Java proxies (EJB, SOAP, and JCA) and session beans. The server code is stored in a J2EE EAR file and the client code is made available as a JAR file.
- Deploy the service implementation. The EAR file is deployed to a test environment and eventually to a production server. The client code is used to access the service.
This article illustrates steps 1 and 2, while step 3 will be covered in Part 2. Steps 4 and 5 are performed as with any enterprise service that is created with the Enterprise Services Toolkit, and they are covered in the existing Application Developer documentation. Part 3 will discuss some of the new run-time features of screenable records that are used when working with 3270 applications.
Setting up to create the service definition
We will begin by creating a service definition using
the 3270 terminal service development tools in the
steps outlined below. Later, we will create an
application to test this service. This service
definition is described using Web Services Description
Language (WSDL). For further information, see the
Terminology section of the WebSphere Studio online
documentation (see Figure 1). Before proceeding, it may
be useful to read the documentation in the Help
Perspective under "Tasks" in the section "Creating a
3270 Terminal Service Definition." Readers should have
a working knowledge of Eclipse and WebSphere Studio
Application Developer.
Figure 1. Information on Enterprise Service Projects
Create a service project
-
Create a new Service project and name it
CICSEPISample
. When the project is created, the Service Providers page will be open. For information on Service projects, see the online documentation.
-
Click the link under
3270 Terminal Services
, in the Service Provider Browser. This will open up the Connection Properties page.
Setting the connection properties
Before we can capture the 3270 screens of the EPI application, we need to provide connection information:
- In the Terminal Service page, specify the port connection properties:
-
Select
CICS EPI
from the drop-down list for the 3270 Service providers. Set the CICS gateway codepage and server names, Host address, properties, and port number values, and any other settings your environment requires. An example is provided in Figure 2 below. Click
Next
.
- Set the properties for the Service Provider connection as in Figure 3 below. These properties will be used by the EPIManagedConnectionFactory, which is explained in the Reference section of the documentation.
-
Click
Add Service
and the 3270 Terminal Service Recorder will open.
Connect to the EPI application
-
Click on the
Connect to Host
icon. At this point, you will be connected to the CICS server, as shown in Figure 4.
-
If a connection cannot be established, click the
Connection Properties
icon and verify that the settings are correct. Also, if there are problems at any point, you can also test the connection or your EPI application using the CICS Client 3270 Terminal Emulator by selecting
Start => Programs => IBMTM CICS Transaction Gateway => CICS Terminal
. Refer to the WebSphere Studio documentation on how to configure this emulator.
Using the terminal editor
We will define our service in terms of the screens from the Menu EPI sample. Before we can do this, we will use the Terminal editor to capture the screens:
The sign-on screen
This not really a sign-on screen, but in most applications, this would be the screen where a user ID and password are entered. In our case, we just want to pass the name of the program we want to invoke, which is the string "MENU."
-
Press the
PF3
and
Clear
buttons at the bottom of the editor. You will get a blank terminal screen. Click the
Import Screen
icon
and enter
SignOn
in the
Screen name
field. Leave
Launch editor
unchecked. Click
OK
. You will see that the blank screen has now been recognized as the SignOn screen. A file called
SignOn.xsd
will be created. When helper classes are created, this will become
SignOn.java
.
-
Type
MENU
in the screen of the Terminal editor, as in Figure 5 below, and press
Enter
.
The menu screen
-
The first screen of the MENU program appears in the terminal. Capture the screen by clicking the
Import Screen
icon and entering
Menu
for the screen name. Check the
Launch
editor
box because this screen requires extra information to be recognized, as explained next. You can also open a screen editor later by double clicking on the respective
.xsd
file (these appear in the Services or Packages view under the project in which you are working). To make the type more usable later when we write code that uses the generated proxy, we will rename some of the fields here. To see where the names we give will be used, see source code listings 1 and 2.
-
The Screen editor will open as in Figure 6 below. In the
Screen Definition
panel, double-click on the empty field next to
ENTER TRANSACTION
. This will highlight the
Field_901
line in the lower window (see Figure 6 below). Next, click on the
Field_901
cell to put it in edit mode and type
transaction
. This will become a field in the Java class (therefore, remember never to use Java keywords!). As you move the mouse off the screen image, other fields will become highlighted, but this doesn't change the focus unless you double-click elsewhere in the table or screen image. Scroll down the table and click the
Field_913
cell (you can double-click on any field in the screen image to locate the respective entry in the table) and change the value to
accountNumber
. Save the file.
-
Click the
Menu
tab and unselect the
Total number of fields
box. We will add the values of certain fields to the screen recognition profile in the next step. This will allow the editor to recognize this screen over other similar screens. This screen should be recognized based on the contents, not the number of fields. The reason is that, if the HOD 3270 resource adapter were used, it would recognize one more field than the CICS EPI resource adapter since it counts the screen wrap-around symbol as one field. In the future, both resource adapters will likely standardize on this point, but it is not certain what convention will be adopted.
-
Double-click the
INSTRUCTIONS C version
line at the top of the screen and do the same for the
PRESS CLEAR TO EXIT
line. Entries for
Field_11
and
Field_802
will appear in the list as in Figure 7. The second entry is important since this line is a message that distinguishes this screen from similar error screens. Other lines may or may not be selected as well; the idea is to have a set of fields that uniquely represents each particular screen. What we have now is sufficient. Save the definition.
-
Switch back to the Terminal Editor. You will see that the Menu screen is now recognized by the editor. Enter
INQY
for the transaction name and a valid account number for your database (you may have to press the Insert key if you find you are unable to enter values into the terminal fields). You can use the BRWS transaction to determine what account numbers are valid, and then return to this screen. Press
Enter
.
The inquiry screen
-
Capture the Inquiry screen by clicking the
Import Screen
icon. Enter
AccountInfo
for the screen name and check
Launch editor
because there will be many fields to edit.
-
In the Screen Definition panel for the Inquiry screen, change the name of
Field_171
,
Field_251
,
Field_331
,
Field_411
,
Field_491
,
Field_571
, and
Field_651
, to
accountNumber
,
name
,
address
,
phone
,
date
,
amount
, and
comment
respectively. Save the file.
-
Click the
AccountInfo
tab, uncheck
Total number of fields
, then double-click on the
FILE INQUIRY
and
PRESS ENTER TO CONTINUE
fields.
Adding an error screen
At this point, we have captured three screens and provided recognition profiles for each. We could move to the next step in creating our EPI Enterprise Service, which is defining the interactions between these screens by recording a dialog, but we will capture one more screen so that we can later show how to handle cases where there are different paths that can be taken in navigating the terminal screens.
-
Switch back to the Terminal editor. Press
Enter
to return to the Menu screen. Enter
INQY
for the transaction, and an account number which does not exist in your database. You can capture the screen that appears as in the previous examples, but since the resulting error screen is related to the Menu screen, we will use an alternate method of creating a screen type: we will just duplicate and make one modification the existing Menu screen type.
-
In the screen that appears, highlight
INVALID NUMBER -- PLEASE REENTER
(use the mouse to swipe the text) and press
Ctrl-Insert
to copy to the clipboard.
-
Open
Menu.xsd
(double-click on the file if it is not already open). Right-click on the
Menu
tab and select
duplicate
. Enter
UnknownAccountNum
in the
Identify as
field. Leave
Menu
in the
Copy from
field. Click on the
Value
cell in the
Field_802
row and paste the text copied from the screen. Make sure to delete all of the previous string including the trailing whitespace. Save the file.
-
Switch back to the Terminal editor again. You should still see Unrecognized Screen in the title. Click the
Reload Screen Recognitions
icon
. You should now see Menu_UnknownAccountNum in the screen title. Whenever a screen definition is ambiguous, the screen title becomes an active drop-down list so that you can select the proper screen name. In general, avoid ambiguous screen definitions by creating a proper screen recognition profile in the first place.
An alternate way to add this additional screen is to set the Invert flag for Field_802 to true (and leave the value as PRESS CLEAR TO EXIT). Depending on how you want the service to work, this may even be better, since any message that appears in this field, other than "PRESS CLEAR TO EXIT," will be recognized as belonging to an error screen.
We now have two possible screen paths in performing an inquiry:
- SignOn => Menu => AccountInfo => Menu => SignOn
- SignOn => Menu => InvalidAccountNum => SignOn
(Actually, in the first case, there were really multiple possible paths because, from the Menu screen, we can obtain the SignOn or AccountInfo screens.) Before we can generate a WSDL file and Java code from our screen captures, we must let the editor know which paths are possible through screen navigations. This is covered in the next section.
Creating a screen dialog
Now we are ready to create a dialog to record the screen interactions. As we record each transition from one screen to another, new operations will be created in the WSDL file. Each operation will represent the action that can be executed to produce an instance of the respective screen data type.
Recording a dialog
We will create a simple dialog that will form a service that can be used to connect to the EPI application and retrieve the data for an account.
-
Press
Clear
to return to the SignOn screen. Click the
Create New Dialog
icon
, then click the
Start Recording Dialog
icon
. Type
MENU
in the screen and press
Enter
. The editor has recorded the fact that the Menu screen type can be obtained from the SignOn type and that the type is obtained by passing a string containing the value "MENU". This is important to understand when you begin working with the Java code that will be generated shortly. Refer to Listing 1 to see how this is used.
-
Type
INQY
and a valid account number in the respective fields of the Menu screen, and then press
Enter
. The editor has now recorded that the AccountInfo screen type can be obtained from the Menu screen type and that two strings are required as parameters:
Transaction
and
AccountNumber
. As we will see in using the generated Java code, we will be able to obtain account information by passing the string "INQY" and an account number string to a method of the Menu type.
-
Press
Enter
to return to the menu, then press
Clear
to sign off. Press the
Stop Recording Dialog
icon
.
-
Click the
Save Dialog
icon
and enter
AccountInfoCICSEPI
for the name of the WSDL file and check
Launch editor
since we will make some changes to this dialog in the next section. If you had continued earlier and repeated the above steps to obtain another account record, multiple actions would have been recorded. These are not necessary and can be deleted later with the Dialog editor.
Editing a dialog
Now we edit the dialog to give more meaningful names to the actions we recorded and to set connection properties.
-
Click on the drop-down list at the top. You will see the screens that have been recognized and recorded to this point. Select
SignOn
and the output screens (those types that are obtainable from the SignOn type) will be shown at the bottom. In this case, the only screen type that can be recognized from SignOn is Menu.
-
Click the
Menu
tab in the dialog editor, then right-click on it. To make the generated code easier to understand for developers, we will change the name of the
Menu
action to
gotoMenu
, so that it looks like a Java method name. The actions that are recorded in the dialog will become operations in the WSDL file and methods in the Java proxy classes (for example, look for
gotoMenu
in Listing 1).
-
Optional. Right-click again on the
gotoMenu
tab and select
Connection Properties
. We can set the
functionName
EPI connection property to
MENU
here so that we don't have to set it in our Java code that will use the proxy later. This does not apply though, if the HOD 3270 resource adapter will be used since it does not have this connection property.
-
Rename the rest of the actions to resemble method names. Select
Menu
from the top drop-down list and rename
SignOn
to
signOn
and
AccountInfo
to
getAccountInfo
. Select
AccountInfo
from the drop-down list and rename
Menu
to
returnToMenu
. Don't forget to save.
Adding more screens to the dialog
We could have continued our dialog recording earlier to include the error screen, but we want to show how more screens can be added after the recording has stopped. There are two ways to do this: one is to use the Add Action icon in the Dialog editor, the other is to do more screen recording. We will do the latter so we can also show how the previously recorded dialog can be used to facilitate further extending the dialog. 
-
Switch back to the Terminal editor and select
AccountInfoCICSEPI
from the drop-down list that is part of the Create New Dialog icon (click on the arrow to the right of it) to reload the changes into the Terminal editor.
-
Click the arrow to the right of the
Play Dialog
icon
and select
gotoMenu
. Hit
OK
in the
Screen Field Prompt
. The string "MENU" is passed to the SignOn screen and the Menu screen appears. At this point, if you inspect the actions that are available in the
Play Dialog
drop-down list, you will see that
signOff
and
getAccountInfo
are actions that can be carried out from the Menu screen. You can select either one to see what happens (by default, the values you used during recording will be passed), but come back to the point where the Menu screen is showing before continuing with the next step.
-
With the Menu screen active, click the
Start Recording Dialog
icon and enter
INQY
and an invalid account number in the respective fields of the screen. Press
Enter
.
-
From the error screen that appears, press
Clear
to exit, then press the
Stop Recording Dialog
icon. Click the
Save Dialog
icon, check
Launch editor
,and hit
OK
.
-
Select
Menu_UnknownAccountNum
from the drop-down list and rename
SignOn
to
signOn
. (Note, if the drop-down list does not have the new error screen added to it, close the editor and reopen it.) Select
Menu
from the drop-down list and delete
Menu_UnknownAccountNum
since it produces the same result as getAccountInfo; we just need this screen as a possible output of the getAccountInfo action. Close the editor and save the changes.
-
Switch back to the Terminal editor and select
AccountInfoCICSEPI
again to reload the dialog changes. You can test your updated dialog by using the
Play Dialog
drop-down list to navigate through all possible paths to ensure that account information can be accessed and that errors can be handled properly (that is, the dialog can be used to continue navigating even when errors occur). Of course, we have only captured one possible type of error; in actual use, we would capture every possible error so that our EPI application can be coded to deal with them. Furthermore, even without considering errors, the number of screens captured, even in simple applications would be much greater and the paths more complex but we want to keep things simple for illustrative purposes.
-
Disconnect from the CICS server by clicking the
Disconnect From Host
icon
.
 |
Testing the EPI account info service
Generating a service proxy
Now that we have created an enterprise service based on the EPI Menu sample, we can deploy it and make it available. In the next article in this series, we will use this service within a flow. Right now, we will create a service proxy and test that our service works as intended. Testing with a JCA proxy should always be done before deploying and creating SOAP or EJB proxies. The following steps are performed to generate the MENU application's JCA proxy:
-
Select the
AccountInfoCICSEPI.wsdl
file and click on the
Create a service proxy
icon
. The Proxy wizard opens with default values based on the contents of the selected service binding file. Change the class name to
AccountInfoCICSEPIProxy
and the package name to
sample.epi.cics
.
Generate helper classes
is selected by default. Your service will need these Java helper classes because you are creating a service that includes complex types. Click
Next
.
-
In the
Service Proxy Style
page, specify the
Client stub proxy style
since we want to expose several operations for our service. Select the
EPIDialogPortType
and all the operations will become checked. Click
Finish
.
AccountInfoCICSEPIProxy.java
is generated in the
CICSSample
project. Both proxy styles and the generated classes are explained further in the WebSphere Studio documentation.
Testing the service proxy
Ultimately, we would like to reference our proxy in a flow, but first we will test our proxy by writing simple client code to execute the proxy.
-
Create a Java class called
TestAccountCICSEPI
in the
sample.epi.cics
package and copy the following code to it.
- Save the changes and run the class. You should see the account info displayed in the console. At this point, you know the logic in creating the service was correct and that the service is ready to be deployed, or in our case, available for use in a flow.
Creating a more complex EPI service
The example above shows a service that is created from relatively simple EPI screens. In the Menu sample, it is possible to browse account information by scrolling forward or backward through the accounts. Creating a service based on this is more complex since data is returned over several screens. Part 2 in this series will show that creating a flow from this type of service presents additional challenges. This section omits details that have been covered above and merely notes the differences in creating a browse service.
Importing the browse screens
The screens that were created above can be reused in this example, so we will just create the new screens that are needed to browse the Menu sample.
-
Open
CICSEPISample.terminal
and reconnect to the CICS server if necessary. Return to the Menu screen of the MENU program.
-
Enter BRWS in the
Transaction
field and leave the
Number
field empty. We want our service to list all accounts, so we will not provide a starting account number. Depending on how your database is populated, you will get a screen similar to the one below.
-
Capture the screen and name it
Browse
.
-
In the screen editor for
Browse.xsd
, select the
Browse
tab. Add the
FILE BROWSE
,
PRESS CLEAR TO END BROWSE OPERATION
, and
PRESS PF1 OR TYPE F TO PAGE FORWARD
fields to the recognition table.
-
Duplicate the
Browse
screen type and name it
BrowseHiEnd
. Since our application will only be scrolling forward to the end of the file, we will not concern ourselves with recognizing hitting the low end of the file. Add the
PRESS PF1
field to the
BrowseHiEnd
screen and change the value to HI-END OF FILE.
-
Select the
Screen Definition
tab and edit the account info fields. Name the fields
accountNumber1
,
name1
,
amount1
,
accountNumber2
,
name2
,
amount2
, and so on for the four sets of fields.
Creating the browse dialog
-
Record a new dialog and name it
AccountBrowseCICSEPI
. Ensure you capture going from SignOn to a Browse screen via the Menu screen, from a Browse screen forward to another Browse screen, and from Browse to SignOff via Menu. Also record going from a Browse screen to the High-End of file screen and from there to the Menu screen. You can try to avoid capturing redundant screen transitions (turn off the record button any time you are about to perform a transition that has already been recorded), or you can delete them afterwards with the Dialog editor.
- Edit the dialog actions (select each one from the drop-down list in the Dialog editor) as follows:
-
If
Browse_BrowseHiEnd
does not appear in the
Outputs
list, then select the Menu screen from the drop-down list again and the select
Browse_BrowseHiEnd
from the drop-down output screen name list. Click
Add
and this screen will be added as a possible output of the Menu screen actions.
- Load the dialog changes into the terminal editor and verify that you can sign on and browse.
This example assumes that your database has enough
entries so that more than one screen will appear. If
this is not the case, use the Dialog editor to add an
action that goes from a Browse screen to another Browse
screen, or to the end of the file. You wouldn't have
had to add the Browse_BrowseHiEnd output screen if you
hit the end of file from the startBrowse action. Also,
if your database has so many entries that it takes
forever to reach the end of the file (not that this is
likely to happen in the Menu sample -- this is more a
tip for real applications), you can stop recording,
return to the Menu screen, and enter a high account
number. Then, when you finally hit the last screen, you
can back up one screen, then re-start recording, and go
again to the last screen.
Testing the EPI browse service
-
Create a proxy for
AccountBrowseCICSEPI.wsdl
. Change the name of the class to
AccountBrowseCICSEPIProxy
and the package to
sample.epi.cics
.
-
Create a new Java class called
TestAccountBrowseCICSEPI
and copy the following code to it. If anything doesn't compile, it is likely because a step was missed in creating and editing the screens and dialogs.
- Save the changes and run the class. You should see all the accounts displayed in the console. At this point, you know the logic in creating the service was correct and the new service is ready to be used.
Debugging the EPI service
This section highlights common problems that occur when testing the new service. In Listing 1, there was a commented-out line: System.out.println(menuOutput._getFormatHandler().toString());
It can be used to determine which screen was returned by the proxy. If the wrong screen is returned, the recognition may have been incorrect. In this case, return to the Terminal Editor, make sure the screen recognition profiles are loaded, then use the dialog to step through the application, checking that exactly one screen is recognized at each step (the screen name appears on the toolbar, and the drop-down list is disabled). You can also open each XSD file in the screen editor and inspect the recognition profiles.
In the proxy, each method (dialog action) opens the port through the resource adapter if the port is not already open. More importantly, if the port was not open at the start of the method, it will be closed at the method's end. Executing an action, for example
getAccountInfo
, with a closed port would result in a sign-on screen being returned and not the AccountInfo screen. This is why we open the port in our test code in the listings above: the same port will be reused during every action execution until we explicitly close it.
If a screen is returned that matches more than one
definition, we get a different type of problem: each
type that was matched will be non-null. For example, in
Listing 2, if the Browse screen could not be
distinguished from the BrowseHiEnd screen, then
browseAtEnd and browse would both be non-null and an
infinite loop would result.
Tip: On machines with certain types of video cards, if NetMeeting Remote Desktop Sharing is enabled, it will prevent WebSphere Studio from establishing a 3270 connection.
Conclusion
Our new service can now be deployed to a J2EE server as with any other enterprise service. However, we would typically represent the screen interactions in a service flow. In Part 2 of this series,
Creating a Flow using CICS EPI Enterprise Services
, we will drop the operations from the
AccountInfoCICSEPI.wsdl
and
AccountBrowseCICSEPI.wsdl
files into a flow.
About the authors
Steve Fang is a Software Developer at the IBM Toronto Laboratory. He is currently working on the WebSphere Studio Application Developer Integration Edition Development Team, which provides the next-generation of Enterprise Access Builder tools. Steve joined IBM after receiving his B.Sc.in Computer Science from the University of Toronto in 2000.
John Green is an Advisory Staff Member at the IBM Toronto Laboratory working on connector architecture and tools. He is an expert on J2EE Connector Architecture and accessing legacy Enterprise Information Systems. John Green joined IBM in 1987, and worked on several other projects prior to working on the tools and libraries to access enterprise applications from Java. He contributed to several releases of VisualAge for Java Enterprise Access Builder, and recently was technical lead for J2EE Connector tooling in WebSphere Studio Application Developer Integration Edition. He received his B.Sc. in Computer Science from Queen's University in Kingston in 1987.
Richard Gregory is a Software Developer at the IBM Toronto Laboratory. He is currently working on the WebSphere Studio Application Developer Integration Edition Development Team. Richard Gregory joined IBM part-time in 1997 and worked in the Centre for Advanced studies on various software re-engineering and distributed systems projects. He joined full-time in 2000 and has contributed to two releases of VisualAge for Java Enterprise Access Builder. He received his B. Sc. in Computer Science from the University of Toronto in 1999 and his MASc. in Electrical and Computer Engineering from the University of Waterloo in 2001.
Top of page
Download | Name | Size | Download method |
|---|
| CICSEPISample.zip | .1 MB | FTP | HTTP |
About the authors  | |  | Steve Fang is a Software Developer at the IBM Toronto Laboratory. He is currently working on
the WebSphere Studio Application Developer Integration Edition Development Team, which provides the next-generation of
Enterprise Access Builder tools. Steve joined IBM after receiving his B.Sc.in Computer Science from the University of
Toronto in 2000. |
 | |  | John Green is a Senior Advisory Development Manager and technical team lead for WebSphere Integration Developer Adapter
tooling. He is an expert on J2EE Connector Architecture, Enterprise Metadata Discovery Specification and accessing Enterprise
Information Systems. John joined IBM in 1987, and worked on several other projects prior to working with adapters in
VisualAge for Java, WebSphere Studio Application Developer Integration Edition, Rational Application Developer, and
WebSphere Integration Developer. He received his B.Sc. in Computer Science from Queen's University in Kingston in 1987 |
 | |  | Richard Gregory is a Software Developer at the IBM Toronto Laboratory. He is currently
working on the WebSphere Studio Application Developer Integration Edition Development Team. Richard Gregory joined IBM
part-time in 1997 and worked in the Centre for Advanced studies on various software re-engineering and distributed
systems projects. He joined full-time in 2000 and has contributed to two releases of VisualAge for Java Enterprise
Access Builder. He received his B. Sc. in Computer Science from the University of Toronto in 1999 and his MASc. in
Electrical and Computer Engineering from the University of Waterloo in 2001. |
Rate this page
|  |