Cherwell Asset Management API Documentation

This web page provides information about the Cherwell Asset Management API. It presents a general overview of the API, details on each interface, and additional topics and examples. The tree control on the left provides navigation of this information.

General Information

These topics provide general information about the API and basics about its use including: Open the tree view to see a list of general topics.

Services

This section lists each service provided by the API. Selecting a service will list the individual interfaces for each function that service provides. Open the tree view to see the list of services.

Additional Information

These topics provide additional information about the CAM API and its use including: Also included is an extended example of creating a purchase. Open the tree view to see a list of general topics.

Release notes

CAM API v2.5 is compatible with Cherwell Asset Management v13.0 and higher.

The following changes were made to the API in v2.5.

Introduction

The CAM API is a collection of web services that allows you to interchange data with external systems. Typical uses might involve:

The following services are provided:

Installation

CAM API v2.5 is for use with Cherwell Asset Management v13.0 and must be installed manually. IIS must also be configured manually. The API is delivered in a file called CAMAPI.zip which can be found in the CAM/ folder of the distribution .ZIP file.

To install the API:

  1. Install Cherwell Asset Management as normal using camsetup.exe.
  2. Extract the contents of the CAMAPI.zip file to the esmweb folder created by setup in the default web site root folder (by default, c:\inetpub\wwwroot\esmweb). This should result in a new folder CAMAPI under esmweb.
  3. In IIS, create a virtual directory pointing to c:\inetpub\wwwroot\esmweb\CAMAPI.
  4. In IIS, create an application pool for CAMAPI (use the same settings as for Purchasing - e.g., in IIS7 and above, Managed Pipeline must be Classic, and on 64bit OSes, Enable 32-Bit Applications must be True).
  5. In IIS, turn the CAMAPI virtual directory into an application pointing to the new application pool.
  6. Modify the web.config file in the CAMAPI folder - set the connectionString property value to use your CAM database (use web.config under Purchasing for reference).
If you are using IIS6, follow these steps:
  1. To allow updating purchasing records, in IIS configure the .svc extension for the CAMAPI virtual directory to allow PUT (by default only GET,POST,HEAD,DEBUG are allowed).
  2. To allow deleting purchasing records:
    1. In IIS, configure the .svc extension for the CAMAPI virtual directory to allow DELETE.
    2. In Windows Explorer, configure Security for the CAMAPI folder to allow the Internet Guest Account these additional permissions: Read & Execute, List Folder Contents, Read.
If you are using IIS7, follow these steps:
  1. Modify the web.config. Uncomment the <system.webServer> section.
  2. In Windows Explorer, configure Security for the CAMAPI folder to allow "[machine name]\IUSR" these permissions: Read & Execute, List Folder Contents, Read, Write.
If you are using IIS8, follow these steps:
  1. Modify the web.config. Uncomment the <system.webServer> section.
  2. In Windows Explorer, configure Security for the CAMAPI folder to allow "[machine name]\IUSR" these permissions: Read & Execute, List Folder Contents, Read, Write.
  3. Configure the .svc handler in Control Panel > Programs and Features > Turn Windows features on or off > .Net Framework 4.5 Advanced Services > WCF Services. Check "HTTP Activation".
  4. You might also need to turn on Windows Forms Authentication. In IIS Manager go to the CAMAPI application and change the Authentication configuration. Enable both Anonymous Authentication and Forms Authentication.

Upgrading

CAM API v2.5 is for use with Cherwell Asset Management v13.0 and must be upgraded manually. The API is delivered in a file called CAMAPI.zip which can be found in the CAM/ folder of the distribution .ZIP file.

To upgrade the API:

  1. Install/Upgrade Cherwell Asset Management as normal using camsetup.exe.
  2. Stop the application pool for CAMAPI. If you have an application pool called ESMAPI, delete it.
  3. Delete the c:\inetpub\wwwroot\esmweb\CAMAPI folder and all its contents. If you have a folder called c:\inetpub\wwwroot\esmweb\ESMAPI, delete it and all of its contents.
  4. Extract the contents of the CAMAPI.zip file to the esmweb folder in the default web site root folder (by default, c:\inetpub\wwwroot\esmweb). This should result in a new folder CAMAPI under esmweb.
  5. Modify the web.config file in the CAMAPI folder - set the connectionString property value to use your CAM database (use web.config under Purchasing for reference).
If you are using IIS6, follow these steps:
  1. In Windows Explorer, configure Security for the CAMAPI folder to allow the Internet Guest Account these additional permissions: Read & Execute, List Folder Contents, Read.
If you are using IIS7, follow these steps:
  1. Modify the web.config. Uncomment the <system.webServer> section.
  2. In Windows Explorer, configure Security for the CAMAPI folder to allow "[machine name]\IUSR" these permissions: Read & Execute, List Folder Contents, Read, Write.
If you are using IIS8, follow these steps:
  1. Modify the web.config. Uncomment the <system.webServer> section.
  2. In Windows Explorer, configure Security for the CAMAPI folder to allow "[machine name]\IUSR" these permissions: Read & Execute, List Folder Contents, Read, Write.

Finally, start the application pool for CAMAPI.

REST design

CAM API is a collection of web services that structures information using REST design principles. This means:

The HTTP message body is XML.

How data is read, added, updated, and deleted

The HTTP verbs GET, POST, PUT, and DELETE are used to tell the web service what it is you want to do. Query parameters and the HTTP message body provide the parametric data required.

Reading data — GET

For the GET request, you just provide a URI. The web service reads the query parameters you provide and returns the requested data if it can.

Each result returned contains a URI field that uniquely identifies each object.

The response is an HTTP status code 200 (OK) if the GET succeeded.

Adding new data — POST

The POST request uses a URI to identify the kind of thing you want to create (such as order/purchase), and an XML message body (using the same schema generated by a GET) to provide the data to initialize the new object. The output of the POST is the XML that describes the new object, including the URI assigned by the system.

To add a new order with several line items, you would first create the order (purchase or lease) and remember its assigned URI. Then you would create any line items, filling in the line item's order URI with the URI of the new order. Then you would do the same for any line item details (serial numbers and assignments).

The response is an HTTP status code 201 (Created) if the POST succeeded.

Updating existing data — PUT

To update existing data, you do a PUT and provide the URI of the record you want to update. You must also provide XML data with updated data for each field in the record. Fields without values will be set to a suitable default.

To guard against updating records that are out of date (have been modified since the last time you read them), there is a VersionStamp field. You must get the current record before updating it, because the update will fail if the VersionStamp doesn't match what is currently saved.

The PUT response is an XML representation of the updated record.

The response is an HTTP status code 200 (OK) if the PUT succeeded.

Deleting existing data — DELETE

To delete something, you simply use a DELETE command with a URI that identifies the record to be deleted. Referential integrity rules will delete any other objects "owned" by what the system deletes.

The response is an HTTP status code 200 (OK) if the object was deleted successfully.

How information is represented

The web service provides and consumes data in XML. A few important notes:

Here is the XML data for a purchase:

<Purchase>
  <Uri>http://myserver/CAMAPI/Order.svc/Purchase/3</Uri>
  <VersionStamp>2</VersionStamp>
  <Date>2010-01-05</Date>
  <Description>Expiring maintenance test</Description>
  <OrderNumber>9290930293029039</OrderNumber>
  <AccessProfile>Purchasing Administrator</AccessProfile>
  <PONumber />
  <TotalPrice>493.00000</TotalPrice>
  <Vendor>
    <Uri />
    <Name>Cherwell Software</Name>
  </Vendor>
  <Notes />
  <CreatedBy>Kathy</CreatedBy>
  <RelatedDocuments />
  <CustomFields>
    <CustomField>
      <Name>Division</Name>
      <Type>Text</Type>
      <Required>False</Required>
      <Value />
    </CustomField>
  </CustomFields>
  <LineItems>
    <Uri>http://myserver/CAMAPI/LineItem.svc/Software/License/219</Uri>
    <Uri>http://myserver/CAMAPI/LineItem.svc/Maintenance/Software/15</Uri>
  </LineItems>
  <InvoiceNumber>54-134</InvoiceNumber>
</Purchase>

Orders are either purchases or leases. In this example each field is labeled with a tag, and references to other things, such as line items, are represented as URIs. The URI for the order itself is provided in the first URI tag. If you present any of these URIs to the web service you will get back whatever the URI addresses.

Here is an example of a software line item:

<SoftwareLineItem>
  <Uri>http://myserver/CAMAPI/LineItem.svc/Software/License/219</Uri>
  <VersionStamp>2</VersionStamp>
  <Order>http://myserver/CAMAPI/Order.svc/Purchase/3</Order>
  <ItemType>Software</ItemType>
  <Name>Microsoft Office</Name>
  <Quantity>3</Quantity>
  <UnitPrice>499.00000</UnitPrice>
  <Status />
  <Contract>http://myserver/CAMAPI/Contract.svc/4</Contract>
  <Notes />
  <CustomFields>
    <CustomField>
      <Name>Location</Name>
      <Type>Text</Type>
      <Required>False</Required>
      <Value />
    </CustomField>
  </CustomFields>
  <Details>
    <Uri>http://myserver/CAMAPI/LineItemDetail.svc/Software/License/39410</Uri>
  </Details>
  <IncludesMaintenance>False</IncludesMaintenance>
  <Attributes>
    <Attribute>
       <Name>IncludesMaintenance</Name>
       <Description>Contract: Includes software maintenance (boolean)</Description>
       <Type>Boolean</Type>
       <Value>False</Value>
    </Attribute>
  </Attributes>
  <ManufacturerName>Microsoft Corporation</Manufacturer>
  <LicenseType>Per seat</LicenseType> 
  <LicenseUnit>
    <Uri>http://myserver/CAMAPI/Inventory.svc/LicenseUnit/261</Uri> 
    <Name>Microsoft Office</Name>
    <Type>License Unit</Type> 
    <Manufacturer>
      <Uri>http://myserver/CAMAPI/Manufacturer.svc/199</Uri> 
      <Name>Microsoft Corporation</Name>
    </Manufacturer>
    <LicenseType>Per seat</LicenseType> 
    <Licenses>5</Licenses> 
    <LastPerUnitCost>499.0000</LastPerUnitCost> 
  </LicenseUnit>
</SoftwareLineItem>

Each line item can itself be composed of a number of detail items. For example, a line item used to purchase five computers may have five detail records for the computers. Here is a line item detail for software:

<SoftwareDetail>
  <Uri>http://myserver/CAMAPI/LineItemDetail.svc/Software/License/39410</Uri> 
  <VersionStamp>2</VersionStamp>
  <LineItem>http://myserver/CAMAPI/LineItem.svc/Software/License/219</LineItem> 
  <Order>http://myserver/CAMAPI/Order.svc/Purchase/3</Order> 
  <Quantity>1</Quantity> 
  <SerialNumber>6493-2944-TOY1-1234</SerialNumber>
  <Assignment /> 
  <AssignmentGroup /> 
  <Notes /> 
  <ReconciledWith /> 
  <ActivationKey /> 
</SoftwareDetail>

And so forth. In each case the URI provides a unique reference to a record that the web service will retrieve when you do an HTTP GET operation.

Authorization

Applications that access CAM via the API do so as the CAM-API user. If Cherwell Asset Management is configured to use CAM authentication, the CAM-API user is pre-defined and has all rights required to call the API. However, if Cherwell Asset Management is configured to use CSM authentication, you must define the CAM-API user within CSM and give it certain rights prior to using the API.

The CAM-API user will then be authenticated by CSM and authorized by the API when invoked.

API Authentication

The CAM API authenticates your requests to identify and verify who is sending the request. If you do not wish to authenticate, then you can edit the web.config file to turn off authentication. Search for "authenticationEnabled" and set its value to "false".

When authentication is enabled, you must provide the following items with each request so the request can be authenticated:

In the request header, you must send an authentication header containing your customer id and the request signature.

Authorization: <Customer ID>:<Signature>

You must also send a date header containing the timestamp. It can either be sent in the Date header or if you cannot set the Date header, then use the x-api-date header.

Date: <timestamp>
-or-
x-api-date: <timestamp>

To calculate your signature, do the following:

  1. Start with the request URL and use only the path and query string. For example: If the request URL is http://myserver/CAMAPI/Order.svc/Purchase?orderby=date then you should only use /CAMAPI/Order.svc/Purchase?orderby=date when calculating the signature. Make sure it is not the URL escaped format of the request. For example, space should not be %20.
  2. Lower case it.
  3. Concatenate the timestamp.
  4. Calculate the HMAC-MD5 signature.
  5. Base64 encode it.

Example:

  1. /CAMAPI/Order.svc/Purchase
  2. /camapi/order.svc/purchase
  3. /camapi/order.svc/purchaseMon, 28 Mar 2016 13:09:22 GMT
  4. Calculate HMAC-MD5 signature. (non-printable)
  5. Base64 encoded result : f+BnSiuw2C3Xpz11yAtpAA==

Request headers for the above example using evaluation customer ID:

x-apiversion: 2.5
Date: Mon, 28 Mar 2016 13:09:22 GMT
Authorization: 0:f+BnSiuw2C3Xpz11yAtpAA==

Java Sample Code for Calculating HMAC-MD5 Signatures. Note: Strings passed into this function are expected to be UTF-8 encoded.

import java.security.SignatureException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class Signature {
   public static String calculateHMAC(String data, String key)
   throws java.security.SignatureException
   {
      String result;
      try {
         // get an hmac_md5 key from the raw key bytes
         SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacMD5");

         // get an hmac_md5 Mac instance and initialize with the signing key
         Mac mac = Mac.getInstance("HmacMD5");
         mac.init(signingKey);

         // compute the hmac on input data bytes
         byte[] rawHmac = mac.doFinal(data.getBytes());

         // base64-encode the hmac
         result = Base64.encode(rawHmac);

      } catch (Exception e) {
         throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
      }
      return result;
   }
}

Versioning

The CAM API checks to ensure that the version of the API that you are using is compatible with your client application. In the request header, send a version header called "x-apiversion" containing the API version number. This header is required and if it is not present or is not the same version as the CAM API, then you will get a 400 (Bad Request) response and the response data will contain the error.

General.svc does not check the version information.

Request header with version information:

x-apiversion: 2.5

Access Profiles

When purchasing user profiles are enabled in the CAM Administrator, you can use access profiles in Purchasing to control who can view, edit, and create orders and contracts. A CAM API application is assumed to be the user "CAM-API" and if purchasing profiles are enabled, "CAM-API" must be a Purchasing administrator or CAM administrator, or in the Purchasing Administrator access profile.

If you add or update an order or contract through the CAM API and purchasing profiles are enabled you must specify an existing access profile. If purchasing profiles are disabled and you do not specify an access profile then it will be assigned to Purchasing Administrators.

For more information see the "Overview: Access profiles" topic in Purchasing help.

Errors

When a web service fails, detailed error descriptions will be returned in the response. Here is an example.

<ErrorCollection>
  <Error>
    <Field>Date</Field>
    <Message>Unable to convert date field.</Message>
  </Error>
  <Error>
    <Field>TotalPrice</Field>
    <Message>Field is not a currency or numeric value.</Message>
  </Error>
  <Error>
    <Field>Custom field value for "Order Number Test 765"</Field>
    <Message>Field is not a numeric value.</Message>
  </Error>
  <Error>
    <Field>InvoiceNumber</Field>
    <Message>The maximum length of the "InvoiceNumber" field is 256 characters.</Message>
  </Error>
</ErrorCollection>

Query Parameters

When doing a GET operation that returns a list of objects, the web service will accept and parse a particular set of query parameters. These are particularly useful when searching for an item or when paging through result sets. The query operations supported are:

Search

The search parameter accepts a column name, a comparison operator, and a constant value to be compared against. For example:

http://myserver/CAMAPI/Order.svc/Purchase?search=vendor+notlike+cdw

In this case the request is to return all purchases whose vendor name is not like "CDW". (The comparison is case-insensitive.)

Columns of all types can be searched on (string, date, number, currency). The comparisons available include equality tests and pattern-matching like comparisons.

Operand Meaning Valid for these types Example
empty Returns record if the field is empty String
Date
search=Description+empty
notempty
!empty
Returns record if the field is not empty String
Date
search= StartDate+notempty
like Returns record if the string specified is contained in the field String search=Description+like+Optiplex
notlike
!like
Returns record if the string specified is not contained in the field String search=Description+notlike+Optiplex
=
eq
Returns record if the field is equal to the parameter String
Number
Currency
Date
License Type
search=Quantity+eq+5
<>
!=
ne
Returns record if the field is not equal to the parameter String
Number
Currency
Date
License Type
search=UnitPrice+ne+100.00
<
lt
Returns record if the field is less than the parameter Number
Currency
Date
search=BuyoutDate+lt+2000-01-10
<=
le
Returns record if the field is less than or equal to the parameter Number
Currency
Date
search=BuyoutDate+le+2000-01-10
>
gt
Returns record if the field is greater than the parameter Number
Currency
Date
search=Quantity+gt+5
>=
ge
Returns record if the field is greater than or equal to the parameter Number
Currency
Date
search=UnitPrice+ge+100.00

Notes:


Orderby

The orderby parameter accepts a column name and an optional direction. The following example lists all leases by lease end date in a descending order.

http://myserver/CAMAPI/Order.svc/Lease?orderby=enddate+desc

Notes:

Page and Size

The page and size parameters provide information about paging lists of results. The default page size is 10. The following example will return the fifth page of twenty results.

http://myserver/CAMAPI/LineItem.svc/Software?page=5&size=20

Custom Fields

You can add values for custom fields in orders and line items through the CAM API. First you need to add the custom field definitions for either orders or line items in Purchasing. Then using either Order.svc or LineItem.svc you can create orders or line items and set the values for your custom fields. The values are Text, Number, Currency, Date, Shortcut, or List depending on your custom field definition.

Example: Create a purchase

This example will create a purchase. It will add a software line item and assign licenses to a machine group. You can also add software maintenance. In this example, Purchasing user policies are disabled so the access profile does not need to be set.

Description

  1. Add a purchase.
  2. Add a software line item with the same name as an existing license unit.
  3. Add the group assignment to the line item.
  4. You can also add software maintenance information to the purchase.

Pseudo code

  1. Add a purchase
    • POST http://myserver/CAMAPI/Order.svc/Purchase
    •     <Purchase> 
            <Date>2010-01-05</Date> 
            <Description>My order</Description> 
            <OrderNumber>9290930293029039</OrderNumber> 
            <PONumber /> 
            <TotalPrice>493.00000</TotalPrice> 
            <Vendor> 
              <Uri /> 
              <Name>Cherwell Software</Name> 
            </Vendor> 
            <Notes /> 
            <CreatedBy>Kathy</CreatedBy>
            <RelatedDocuments /> 
            <InvoiceNumber>54-134</InvoiceNumber> 
          </Purchase>
          
    • Check to make sure that the response code is 201 Created. The content that is returned will look like this:
          <Purchase>
            <Uri>http://myserver/CAMAPI/Order.svc/Purchase/23163</Uri>
            <VersionStamp>1</VersionStamp>
            <Date>2010-01-05</Date>
            <Description>My order</Description>
            <OrderNumber>9290930293029039</OrderNumber>
            <AccessProfile>Purchasing Administrator</AccessProfile>
            <PONumber />
            <TotalPrice>493.00000</TotalPrice>
            <Vendor>
              <Uri>http://myserver/CAMAPI/Manufacturer.svc/27</Uri>
              <Name>Cherwell Software</Name>
            </Vendor>
            <Notes />
            <CreatedBy>Kathy</CreatedBy>
            <RelatedDocuments />
            <CustomFields />
            <LineItems />
            <InvoiceNumber>54-134</InvoiceNumber>
          </Purchase>
          

      Notice that the URI of the vendor was filled in because the name matched a manufacturer in the CAM database.

    • Get the Purchase URI from the returned content.
  2. Add a software line item with the same name as an existing license unit using the Purchase URI from Step 1 as the value for the Order element.
    • POST http://myserver/CAMAPI/LineItem.svc/Software/License
    •     <SoftwareLineItem>
            <Order>http://myserver/CAMAPI/Order.svc/Purchase/23163</Order>
            <Name>Microsoft Office</Name>
            <Quantity>3</Quantity>
            <UnitPrice>500.00</UnitPrice>
            <Status></Status>
            <Notes></Notes>
            <ManufacturerName></ManufacturerName>
            <LicenseType>Unmanaged</LicenseType>
          </SoftwareLineItem>
          

      If the Name matches an existing License Unit name, this line item will be automatically reconciled after it is created.

    • Check to make sure that the response code is 201 Created. The content that is returned will look like this:
          <SoftwareLineItem>
            <Uri>http://myserver/CAMAPI/LineItem.svc/Software/License/38075</Uri>
            <VersionStamp>1</VersionStamp>
            <Order>http://myserver/CAMAPI/Order.svc/Purchase/23163</Order>
            <ItemType>Software</ItemType>
            <Name><![CDATA[CAM Purchasing]]></Name>
            <Quantity>3</Quantity>
            <UnitPrice>500.00</UnitPrice>
            <Status />
            <Notes />
            <Details />
            <ManufacturerName />
            <LicenseType>Unmanaged</LicenseType>
            <LicenseUnit i:nil="true" />
          </SoftwareLineItem>
          
    • Notice that the line item has not been reconciled yet. Reconciliation happens on a SQL trigger so you will need to GET the line item again (step 3) to see whether it has been reconciled or not.

    • Get the Line Item URI from the returned content.
  3. Add the group assignment to the line item.
    • Get the URI for the group that you want to assign to.
      GET http://myserver/CAMAPI/Group.svc/Machine?search=Name+eq+Marketing
          <ItemCollection>
            <Group>
              <Uri>http://myserver/CAMAPI/Group.svc/Machine/327</Uri>
              <Type>Machine Group</Type>
              <Name><![CDATA[Marketing]]></Name>
            </Group>
          </ItemCollection>
          
    • Add the group assignment detail to the line item.
      POST http://myserver/CAMAPI/LineItemDetail.svc/Software/License
          <SoftwareDetail>
            <LineItem>
              http://myserver/CAMAPI/LineItem.svc/Software/License/38075
            </LineItem>
            <Quantity>3</Quantity>
            <AssignmentGroup>http://myserver/CAMAPI/Group.svc/Machine/327</AssignmentGroup>
          </SoftwareDetail>
          
  4. You can also add software maintenance information to the purchase. Add a software maintenance line item with the same name as an existing license unit, using the Purchase URI from Step 1 as the value for the Order element.
    • POST http://myserver/CAMAPI/LineItem.svc/Maintenance/Software
          <SoftwareMaintenanceLineItem>
            <Order>http://myserver/CAMAPI/Order.svc/Purchase/23163</Order>
            <Name>Microsoft Office</Name>
            <Quantity>6</Quantity>
            <UnitPrice>100.00</UnitPrice>
            <Status>
            </Status>
            <Notes>
            </Notes>
            <Manufacturer>
              <Name>My manufacturer</Name>
            </Manufacturer>
            <StartDate>2011-03-11</StartDate>
            <EndDate>2012-03-10</EndDate>
            <ContractNumber>
            </ContractNumber>
            <ServiceDescription>
            </ServiceDescription>
            <MaintainedLicenseUnit>
              http://myserver/CAMAPI/Inventory.svc/LicenseUnit/162
            </MaintainedLicenseUnit>
          </SoftwareMaintenanceLineItem>
          
    • Check to make sure that the response code is 201 Created. The content that is returned will look like this:
          <SoftwareMaintenanceLineItem>
            <Uri>http://myserver/CAMAPI/LineItem.svc/Maintenance/Software/66933</Uri>
            <VersionStamp>1</VersionStamp>
            <Order>http://myserver/CAMAPI/Order.svc/Purchase/23163</Order>
            <ItemType>Software Maintenance</ItemType>
            <Name>Microsoft Office</Name>
            <Quantity>6</Quantity>
            <UnitPrice>100.00000</UnitPrice>
            <Status/>
            <Notes/>
            <CustomFields>
              <CustomField>
                <Name><![CDATA[CAM$$LicenseAssignmentGroup]]></Name>
                <Type>Text</Type>
                <Required>False</Required>
                <Value/>
              </CustomField>
            </CustomFields>
            <Details/>
            <Manufacturer>
              <Uri/>
              <Name><![CDATA[My manufacturer]]></Name>
            </Manufacturer>
            <StartDate>2011-03-11</StartDate>
            <EndDate>2012-03-10</EndDate>
            <ContractNumber/>
            <ServiceDescription/>
            <MaintainedLicenseUnit>
              http://myserver/CAMAPI/Inventory.svc/LicenseUnit/162
            </MaintainedLicenseUnit>
          </SoftwareMaintenanceLineItem>