diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/conf.py | 6 | ||||
-rw-r--r-- | docs/guide/developer-guide.rst | 30 | ||||
-rw-r--r-- | docs/offeredapis/offeredapis.rst | 17 | ||||
-rw-r--r-- | docs/offeredapis/swagger/a1-adapter-api.json | 378 | ||||
-rw-r--r-- | docs/offeredapis/swagger/a1-adapter-api.yaml | 306 |
5 files changed, 717 insertions, 20 deletions
diff --git a/docs/conf.py b/docs/conf.py index bb52b59d..29923a05 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,6 +15,12 @@ redoc = [ 'page': 'offeredapis/pms-api', 'spec': './offeredapis/swagger/pms-api.json', 'embed': True, + }, + { + 'name': 'A1 ADAPTER API', + 'page': 'offeredapis/a1-adapter-api', + 'spec': './offeredapis/swagger/a1-adapter-api.json', + 'embed': True, } ] diff --git a/docs/guide/developer-guide.rst b/docs/guide/developer-guide.rst index b6d4ce88..f067a3fa 100644 --- a/docs/guide/developer-guide.rst +++ b/docs/guide/developer-guide.rst @@ -36,6 +36,7 @@ The Policy Management Service can be accessed over the REST API. See :ref:`pms_a Dependencies ------------ + This project uses various frameworks which are managed with Maven dependency management tool (see *pom.xml* file at root level) : @@ -59,16 +60,21 @@ that are available. The second contains logging and security configurations. Configuration of certs ---------------------- -The Policy Management Service uses the default keystore and truststore that are built into the container. The paths and passwords for these stores are located in a yaml file: - oran/a1-policy-management/config/application.yaml +The Policy Management Service uses the default keystore and truststore that are built into the container. The paths and +passwords for these stores are located in a yaml file: :: + + oran/a1-policy-management/config/application.yaml -There is also Policy Management Service's own cert in the default truststore for mocking purposes and unit-testing (ApplicationTest.java). +There is also Policy Management Service's own cert in the default truststore for mocking purposes and unit-testing +(ApplicationTest.java). -The default keystore, truststore, and application.yaml files can be overridden by mounting new files using the "volumes" field of docker-compose or docker run command. +The default keystore, truststore, and application.yaml files can be overridden by mounting new files using the "volumes" +field of docker-compose or docker run command. -Assuming that the keystore, truststore, and application.yaml files are located in the same directory as docker-compose, the volumes field should have these entries: +Assuming that the keystore, truststore, and application.yaml files are located in the same directory as docker-compose, +the volumes field should have these entries: :: -`volumes:` + `volumes:` `- ./new_keystore.jks:/opt/app/policy-agent/etc/cert/keystore.jks:ro` `- ./new_truststore.jks:/opt/app/policy-agent/etc/cert/truststore.jks:ro` @@ -77,13 +83,13 @@ Assuming that the keystore, truststore, and application.yaml files are located i The target paths in the container should not be modified. -Example docker run command for mounting new files (assuming they are located in the current directory): +Example docker run command for mounting new files (assuming they are located in the current directory): :: -`docker run -p 8081:8081 -p 8433:8433 --name=policy-agent-container --network=nonrtric-docker-net --volume "$PWD/new_keystore.jks:/opt/app/policy-agent/etc/cert/keystore.jks" --volume "$PWD/new_truststore.jks:/opt/app/policy-agent/etc/cert/truststore.jks" --volume "$PWD/new_application.yaml:/opt/app/policy-agent/config/application.yaml" o-ran-sc/nonrtric-policy-agent:2.1.0-SNAPSHOT` + docker run -p 8081:8081 -p 8433:8433 --name=policy-agent-container --network=nonrtric-docker-net --volume "$PWD/new_keystore.jks:/opt/app/policy-agent/etc/cert/keystore.jks" --volume "$PWD/new_truststore.jks:/opt/app/policy-agent/etc/cert/truststore.jks" --volume "$PWD/new_application.yaml:/opt/app/policy-agent/config/application.yaml" o-ran-sc/nonrtric-policy-agent:2.1.0-SNAPSHOT -A1 Adapter -++++++++++ +A1 Adapter (Internal) ++++++++++++++++++++++ -TBD +The O-RAN A1 Adapter provides an internal REST CONF API for management of A1 policices, useful for test and verification. -The A1 Adapter can be accessed over the REST API. See :ref:`offered_apis` for how to use the API. +The A1 Adapter can be accessed over the REST CONF API. See :ref:`a1_adapter_api` for how to use the API. diff --git a/docs/offeredapis/offeredapis.rst b/docs/offeredapis/offeredapis.rst index c3a7c95f..08126c0d 100644 --- a/docs/offeredapis/offeredapis.rst +++ b/docs/offeredapis/offeredapis.rst @@ -12,7 +12,7 @@ Offered APIs Introduction ************ -The north bound ... +The north bound REST API of the Policy Management Service provides convenient methods to handle policies. Global ORAN architecture @@ -25,17 +25,11 @@ integration with other ONAP components and API resource/operation provided. :width: 500pt -API Endpoint -************ - -TBD - - API Version *********** APIs are described with a state version with "v" following the API Name, -e.g.: ``TBD``. +e.g.: ``v2/policy``. The schema associated with a REST API must have its version number aligned with that of the REST API. @@ -77,6 +71,7 @@ API Table :widths: 10,5, 5 "PMS API", ":download:`link <./swagger/pms-api.json>`", ":download:`link <./swagger/pms-api.yaml>`" + "A1 ADAPTER API (Internal)", ":download:`link <./swagger/a1-adapter-api.json>`", ":download:`link <./swagger/a1-adapter-api.yaml>`" .. _pms_api: @@ -85,3 +80,9 @@ PMS API ....... `PMS API <./pms-api.html>`_ +.. _a1_adapter_api: + +A1 ADAPTER API +.............. +`A1 ADAPTER API (Internal) <./a1-adapter-api.html>`_ + diff --git a/docs/offeredapis/swagger/a1-adapter-api.json b/docs/offeredapis/swagger/a1-adapter-api.json new file mode 100644 index 00000000..12951279 --- /dev/null +++ b/docs/offeredapis/swagger/a1-adapter-api.json @@ -0,0 +1,378 @@ +{ + "apiVersion": "1.0.0", + "swagger": "2.0", + "basePath": "/", + "info": { + "x-audience": "external-partner", + "contact": { + "name": "Ericsson Software Technology", + "email": "nonrtric@est.tech" + }, + "description": "The O-RAN A1 Adapter provides an internal REST CONF API for management of A1 policices, useful for test and verification. <b>Note!</b> For production, the https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html should be used!", + "title": "A1 Adapter", + "version": "1.1.0" + }, + "paths": { + "/restconf/operations/A1-ADAPTER-API:putA1Policy": {"post": { + "summary": "Create or update a policy", + "description": "<b>Note!</b> For production, the https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html PUT /policy method should be used!", + "nickname": "putA1Policy", + "produces": "application/json", + "responses": { + "200": { + "schema": {"$ref": "#/models/(putA1Policy)output"}, + "description": "Policy created/updated", + "examples": { + "application/json": { + "A1-ADAPTER-API:body": {}, + "A1-ADAPTER-API:http-status": 200 + } + } + } + }, + "parameters": [ + { + "schema": {"$ref": "#/models/(putA1Policy)input"}, + "in": "body", + "name": null, + "description": null, + "required": false + } + ] + } + }, + "/operations/A1-ADAPTER-API:getA1Policy": {"post": { + "summary": "Get policy configuration/s", + "description": "<b>Note!</b> For production, the https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html GET /policy method should be used!", + "nickname": "getA1Policy", + "produces": "application/json", + "responses": { + "200": { + "schema": {"$ref": "#/models/(getA1Policy)output"}, + "description": "Policy found", + "examples": { + "application/json": { + "A1-ADAPTER-API:body": { + "id": "Policy 1", + "json": { + "scope": { + "ueId": "UE1 ", + "cellId": "Cell 1" + }, + "qosObjectives": { + "gfbr": 319.5, + "mfbr": 782.75, + "priorityLevel": 268.5, + "pdb": 44.0 + }, + "qoeObjectives": { + "qoeScore": 329.0, + "initialBuffering": 27.75, + "reBuffFreq": 539.0, + "stallRatio": 343.0 + }, + "resources": [] + }, + "ownerServiceName": "Service 1", + "ric": "ric1", + "type": "STD_PolicyModelUnconstrained_0.2.0", + "lastModified": "Wed, 01 Apr 2020 07:45:45 GMT" + }, + "A1-ADAPTER-API:http-status": 200 + } + } + } + }, + "parameters": [ + { + "schema": {"$ref": "#/models/(getA1Policy)input"}, + "in": "body", + "name": null, + "description": null, + "required": false + } + ] + } + }, + "/restconf/operations/A1-ADAPTER-API:getA1PolicyStatus": {"post": { + "summary": "Get a policy status", + "description": "<b>Note!</b> For production, the https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html GET /policy-status method should be used!", + "nickname": "getA1PolicyStatus", + "produces": "application/json", + "responses": { + "200": { + "schema": {"$ref": "#/models/(getA1PolicyStatus)output"}, + "description": "Policy status", + "examples": { + "application/json": { + "A1-ADAPTER-API:body": { + "enforceStatus": "UNDEFINED" + }, + "A1-ADAPTER-API:http-status": 200 + } + } + } + }, + "parameters": [ + { + "schema": {"$ref": "#/models/(getA1PolicyStatus)input"}, + "in": "body", + "name": null, + "description": null, + "required": false + } + ] + } + }, + "/restconf/operations/A1-ADAPTER-API:getA1PolicyType": {"post": { + "summary": "Get a policy type schema definition", + "description": "<b>Note!</b> For production, the https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html GET /policy-types method should be used!", + "nickname": "getA1PolicyType", + "produces": "application/json", + "responses": { + "200": { + "schema": {"$ref": "#/models/(getA1PolicyType)output"}, + "description": "Policy schema", + "examples": { + "application/json": { + "A1-ADAPTER-API:body": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Example_QoETarget_1.0.0", + "description": "Example QoE Target policy type", + "type": "object", + "properties": { + "scope": { + "type": "object", + "properties": { + "ueId": { + "type": "string" + }, + "sliceId": { + "type": "string" + }, + "qosId": { + "type": "string" + }, + "cellId": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "ueId", + "sliceId" + ] + }, + "statement": { + "type": "object", + "properties": { + "qoeScore": { + "type": "number" + }, + "initialBuffering": { + "type": "number" + }, + "reBuffFreq": { + "type": "number" + }, + "stallRatio": { + "type": "number" + } + }, + "minProperties": 1, + "additionalProperties": false + } + } + }, + "A1-ADAPTER-API:http-status": 200 + } + } + } + }, + "parameters": [ + { + "schema": {"$ref": "#/models/(getA1PolicyType)input"}, + "in": "body", + "name": null, + "description": null, + "required": false + } + ] + } + }, + "/restconf/operations/A1-ADAPTER-API:deleteA1Policy": {"post": { + "summary": "Delete a policy", + "description": "<b>Note!</b> For production, the https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html DELETE /policy method should be used!", + "nickname": "deleteA1Policy", + "produces": "application/json", + "responses": { + "200": { + "schema": {"$ref": "#/models/(deleteA1Policy)output"}, + "description": "Policy deleted", + "examples": { + "application/json": { + "A1-ADAPTER-API:body": {}, + "A1-ADAPTER-API:http-status": 200 + } + } + } + }, + "parameters": [ + { + "schema": {"$ref": "#/models/(deleteA1Policy)input"}, + "in": "body", + "name": null, + "description": null, + "required": false + } + ] + } + } + }, + "models": { + "(putA1Policy)input": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:near-rt-ric-url": { + "required": false, + "type": "Some near-rt-ric-url", + "example": "http://nearRtRic-sim1:8085/a1-p/policytypes/11/policies/5000" + }, + "A1-ADAPTER-API:body": { + "required": false, + "type": "Some body", + "example": { + "blocking_rate":20, + "enforce":true, + "trigger_threshold":10, + "window_length":10 + } + } + }, + "id": "(putA1Policy)input" + }, + "(putA1Policy)output": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:body": { + "required": false, + "type": "Some body" + }, + "A1-ADAPTER-API:http-status": { + "required": false, + "type": "-2147483648" + } + }, + "id": "(putA1Policy)output" + }, + "(getA1Policy)input": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:near-rt-ric-url": { + "required": false, + "type": "Some near-rt-ric-url", + "example": "http://localhost:8081/policy?id=Policy 1" + } + }, + "id": "(getA1Policy)input" + }, + "(getA1Policy)output": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:body": { + "required": false, + "type": "object" }, + "A1-ADAPTER-API:http-status": { + "required": false, + "type": "-2147483648" + } + }, + "id": "(getA1Policy)output" + }, + "(getA1PolicyStatus)input": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:near-rt-ric-url": { + "required": false, + "type": "Some near-rt-ric-url", + "example": "http://ricsim_g2_1:8085/A1-P/v1/policies/5000/status" + } + }, + "id": "(getA1PolicyStatus)input" + }, + "(getA1PolicyStatus)output": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:body": { + "required": false, + "type": "Some body" + }, + "A1-ADAPTER-API:http-status": { + "required": false, + "type": "-2147483648" + } + }, + "id": "(getA1PolicyStatus)output" + }, + "(getA1PolicyType)input": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:near-rt-ric-url": { + "required": false, + "type": "Some near-rt-ric-url", + "example": "http://nearRtRic-sim1:8085/a1-p/policytypes/11" + } + }, + "id": "(getA1PolicyType)input" + }, + "(getA1PolicyType)output": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:body": { + "required": false, + "type": "Some body" + }, + "A1-ADAPTER-API:http-status": { + "required": false, + "type": "-2147483648" + } + }, + "id": "(getA1PolicyType)output" + }, + "(deleteA1Policy)input": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:near-rt-ric-url": { + "required": false, + "type": "Some near-rt-ric-url", + "example": "http://localhost:8282/restconf/operations/A1-ADAPTER-API:deleteA1Policy" + } + }, + "id": "(deleteA1Policy)input" + }, + "(deleteA1Policy)output": { + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "A1-ADAPTER-API:body": { + "required": false, + "type": "Some body" + }, + "A1-ADAPTER-API:http-status": { + "required": false, + "type": "-2147483648" + } + }, + "id": "(deleteA1Policy)output" + } + } +}
\ No newline at end of file diff --git a/docs/offeredapis/swagger/a1-adapter-api.yaml b/docs/offeredapis/swagger/a1-adapter-api.yaml new file mode 100644 index 00000000..1db84156 --- /dev/null +++ b/docs/offeredapis/swagger/a1-adapter-api.yaml @@ -0,0 +1,306 @@ +apiVersion: 1.0.0 +swagger: '2.0' +basePath: / +info: + x-audience: external-partner + contact: + name: Ericsson Software Technology + email: nonrtric@est.tech + description: >- + The O-RAN A1 Adapter provides an internal REST API for management of A1 + policices, useful for test and verification. <b>Note!</b> For production, + the + https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html + should be used! + title: A1 Adapter + version: 1.1.0 +paths: + '/restconf/operations/A1-ADAPTER-API:putA1Policy': + post: + summary: Create or update a policy + description: >- + <b>Note!</b> For production, the + https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html + PUT /policy method should be used! + nickname: putA1Policy + produces: application/json + responses: + '200': + schema: + $ref: '#/models/(putA1Policy)output' + description: Policy created/updated + examples: + application/json: + 'A1-ADAPTER-API:body': {} + 'A1-ADAPTER-API:http-status': 200 + parameters: + - schema: + $ref: '#/models/(putA1Policy)input' + in: body + name: null + description: null + required: false + '/operations/A1-ADAPTER-API:getA1Policy': + post: + summary: Get policy configuration/s + description: >- + <b>Note!</b> For production, the + https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html + GET /policy method should be used! + nickname: getA1Policy + produces: application/json + responses: + '200': + schema: + $ref: '#/models/(getA1Policy)output' + description: Policy found + examples: + application/json: + 'A1-ADAPTER-API:body': + id: Policy 1 + json: + scope: + ueId: 'UE1 ' + cellId: Cell 1 + qosObjectives: + gfbr: 319.5 + mfbr: 782.75 + priorityLevel: 268.5 + pdb: 44 + qoeObjectives: + qoeScore: 329 + initialBuffering: 27.75 + reBuffFreq: 539 + stallRatio: 343 + resources: [] + ownerServiceName: Service 1 + ric: ric1 + type: STD_PolicyModelUnconstrained_0.2.0 + lastModified: 'Wed, 01 Apr 2020 07:45:45 GMT' + 'A1-ADAPTER-API:http-status': 200 + parameters: + - schema: + $ref: '#/models/(getA1Policy)input' + in: body + name: null + description: null + required: false + '/restconf/operations/A1-ADAPTER-API:getA1PolicyStatus': + post: + summary: Get a policy status + description: >- + <b>Note!</b> For production, the + https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html + GET /policy-status method should be used! + nickname: getA1PolicyStatus + produces: application/json + responses: + '200': + schema: + $ref: '#/models/(getA1PolicyStatus)output' + description: Policy status + examples: + application/json: + 'A1-ADAPTER-API:body': + enforceStatus: UNDEFINED + 'A1-ADAPTER-API:http-status': 200 + parameters: + - schema: + $ref: '#/models/(getA1PolicyStatus)input' + in: body + name: null + description: null + required: false + '/restconf/operations/A1-ADAPTER-API:getA1PolicyType': + post: + summary: Get a policy type schema definition + description: >- + <b>Note!</b> For production, the + https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html + GET /policy-types method should be used! + nickname: getA1PolicyType + produces: application/json + responses: + '200': + schema: + $ref: '#/models/(getA1PolicyType)output' + description: Policy schema + examples: + application/json: + 'A1-ADAPTER-API:body': + $schema: 'http://json-schema.org/draft-07/schema#' + title: Example_QoETarget_1.0.0 + description: Example QoE Target policy type + type: object + properties: + scope: + type: object + properties: + ueId: + type: string + sliceId: + type: string + qosId: + type: string + cellId: + type: string + additionalProperties: false + required: + - ueId + - sliceId + statement: + type: object + properties: + qoeScore: + type: number + initialBuffering: + type: number + reBuffFreq: + type: number + stallRatio: + type: number + minProperties: 1 + additionalProperties: false + 'A1-ADAPTER-API:http-status': 200 + parameters: + - schema: + $ref: '#/models/(getA1PolicyType)input' + in: body + name: null + description: null + required: false + '/restconf/operations/A1-ADAPTER-API:deleteA1Policy': + post: + summary: Delete a policy + description: >- + <b>Note!</b> For production, the + https://docs.onap.org/projects/onap-ccsdk-oran/en/latest/offeredapis/pms-api.html + DELETE /policy method should be used! + nickname: deleteA1Policy + produces: application/json + responses: + '200': + schema: + $ref: '#/models/(deleteA1Policy)output' + description: Policy deleted + examples: + application/json: + 'A1-ADAPTER-API:body': {} + 'A1-ADAPTER-API:http-status': 200 + parameters: + - schema: + $ref: '#/models/(deleteA1Policy)input' + in: body + name: null + description: null + required: false +models: + (putA1Policy)input: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:near-rt-ric-url': + required: false + type: Some near-rt-ric-url + example: 'http://nearRtRic-sim1:8085/a1-p/policytypes/11/policies/5000' + 'A1-ADAPTER-API:body': + required: false + type: Some body + example: + blocking_rate: 20 + enforce: true + trigger_threshold: 10 + window_length: 10 + id: (putA1Policy)input + (putA1Policy)output: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:body': + required: false + type: Some body + 'A1-ADAPTER-API:http-status': + required: false + type: '-2147483648' + id: (putA1Policy)output + (getA1Policy)input: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:near-rt-ric-url': + required: false + type: Some near-rt-ric-url + example: 'http://localhost:8081/policy?id=Policy 1' + id: (getA1Policy)input + (getA1Policy)output: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:body': + required: false + type: object + 'A1-ADAPTER-API:http-status': + required: false + type: '-2147483648' + id: (getA1Policy)output + (getA1PolicyStatus)input: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:near-rt-ric-url': + required: false + type: Some near-rt-ric-url + example: 'http://ricsim_g2_1:8085/A1-P/v1/policies/5000/status' + id: (getA1PolicyStatus)input + (getA1PolicyStatus)output: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:body': + required: false + type: Some body + 'A1-ADAPTER-API:http-status': + required: false + type: '-2147483648' + id: (getA1PolicyStatus)output + (getA1PolicyType)input: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:near-rt-ric-url': + required: false + type: Some near-rt-ric-url + example: 'http://nearRtRic-sim1:8085/a1-p/policytypes/11' + id: (getA1PolicyType)input + (getA1PolicyType)output: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:body': + required: false + type: Some body + 'A1-ADAPTER-API:http-status': + required: false + type: '-2147483648' + id: (getA1PolicyType)output + (deleteA1Policy)input: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:near-rt-ric-url': + required: false + type: Some near-rt-ric-url + example: >- + http://localhost:8282/restconf/operations/A1-ADAPTER-API:deleteA1Policy + id: (deleteA1Policy)input + (deleteA1Policy)output: + $schema: 'http://json-schema.org/draft-04/schema' + type: object + properties: + 'A1-ADAPTER-API:body': + required: false + type: Some body + 'A1-ADAPTER-API:http-status': + required: false + type: '-2147483648' + id: (deleteA1Policy)output |