VOL-3157: Initial version of the protos

Change-Id: I8ffda169132f80a51632c52dd8ac142efef26ef7
diff --git a/protos/dmi/commons.proto b/protos/dmi/commons.proto
new file mode 100644
index 0000000..828f5cf
--- /dev/null
+++ b/protos/dmi/commons.proto
@@ -0,0 +1,21 @@
+syntax = "proto3";
+
+option go_package = "github.com/opencord/device-management-interface/v3/go/dmi";
+package dmi;
+
+// Common structures used across the different Device Management services
+
+enum Status {
+    UNDEFINED_STATUS = 0;
+    OK = 1;
+    ERROR = 2;
+}
+
+// Reason for the failure of request
+enum Reason {
+    UNDEFINED_REASON = 0;
+    UNKNOWN_DEVICE = 1;
+    INTERNAL_ERROR = 2;
+    WRONG_METRIC = 3;
+    WRONG_EVENT = 4;
+}
diff --git a/protos/dmi/hw.proto b/protos/dmi/hw.proto
new file mode 100644
index 0000000..efc1400
--- /dev/null
+++ b/protos/dmi/hw.proto
@@ -0,0 +1,194 @@
+syntax = "proto3";

+

+option go_package = "github.com/opencord/device-management-interface/v3/go/dmi";

+package dmi;

+

+import "google/protobuf/timestamp.proto";

+

+// The model used to represent a HW is based on RFC8348 (https://tools.ietf.org/html/rfc8348)

+

+message Uuid {

+    string uuid = 1;

+}

+

+message HardwareID {

+    Uuid uuid = 1;

+}

+

+message Uri {

+    string uri = 1;

+}

+

+enum ComponentType {

+    COMPONENT_TYPE_UNDEFINED = 0;

+    COMPONENT_TYPE_UNKNOWN = 1;

+    COMPONENT_TYPE_CHASSIS = 2;

+    COMPONENT_TYPE_BACKPLANE = 3;

+    COMPONENT_TYPE_CONTAINER = 4;

+    COMPONENT_TYPE_POWER_SUPPLY = 5;

+    COMPONENT_TYPE_FAN = 6;

+    COMPONENT_TYPE_SENSOR = 7;

+    COMPONENT_TYPE_MODULE = 8;

+    COMPONENT_TYPE_PORT = 9;

+    COMPONENT_TYPE_CPU = 10;

+    COMPONENT_TYPE_BATTERY = 11;

+    COMPONENT_TYPE_STORAGE = 12;

+    COMPONENT_TYPE_MEMORY = 13;

+    COMPONENT_TYPE_TRANSCEIVER = 14;

+}

+

+enum ComponentAdminState {

+    COMP_ADMIN_STATE_UNDEFINED = 0;

+    COMP_ADMIN_STATE_UNKNOWN = 1;

+    COMP_ADMIN_STATE_LOCKED = 2;

+    COMP_ADMIN_STATE_SHUTTING_DOWN = 3;

+    COMP_ADMIN_STATE_UNLOCKED = 4;

+}

+

+enum ComponentOperState {

+    COMP_OPER_STATE_UNDEFINED = 0;

+    COMP_OPER_STATE_UNKNOWN = 1;

+    COMP_OPER_STATE_DISABLED = 2;

+    COMP_OPER_STATE_ENABLED = 3;

+    COMP_OPER_STATE_TESTING = 4;

+}

+

+enum ComponentUsageState {

+    COMP_USAGE_STATE_UNDEFINED = 0;

+    COMP_USAGE_STATE_UNKNOWN = 1;

+    COMP_USAGE_STATE_IDLE = 2;

+    COMP_USAGE_STATE_ACTIVE = 3;

+    COMP_USAGE_STATE_BUSY = 4;

+}

+

+enum ComponentAlarmState {

+    COMP_ALARM_STATE_UNDEFINED = 0;

+    COMP_ALARM_STATE_UNKNOWN = 1;

+    COMP_ALARM_STATE_UNDER_REPAIR= 2;

+    COMP_ALARM_STATE_CRITICAL = 3;

+    COMP_ALARM_STATE_MAJOR = 4;

+    COMP_ALARM_STATE_MINOR = 5;

+    COMP_ALARM_STATE_WARNING = 6;

+    COMP_ALARM_STATE_INTERMEDIATE = 7;

+}

+

+enum ComponentStandbyState {

+    COMP_STANDBY_STATE_UNDEFINED = 0;

+    COMP_STANDBY_STATE_UNKNOWN = 1;

+    COMP_STANDBY_STATE_HOT = 2;

+    COMP_STANDBY_STATE_COLD = 3;

+    COMP_STANDBY_STATE_PROVIDING_SERVICE = 4;

+}

+

+message ComponentState {

+    google.protobuf.Timestamp state_last_changed = 1;

+    ComponentAdminState admin_state = 2;

+    ComponentOperState oper_state = 3;

+    ComponentUsageState usage_state = 4;

+    ComponentAlarmState alarm_state = 5;

+    ComponentStandbyState standby_state = 6;

+}

+

+enum SensorValueType {

+    SENSOR_VALUE_TYPE_UNDEFINED = 0;

+    SENSOR_VALUE_TYPE_OTHER = 1;

+    SENSOR_VALUE_TYPE_UNKNOWN = 2;

+    SENSOR_VALUE_TYPE_VOLTS_AC = 3;

+    SENSOR_VALUE_TYPE_VOLTS_DC = 4;

+    SENSOR_VALUE_TYPE_AMPERES = 5;

+    SENSOR_VALUE_TYPE_WATTS = 6;

+    SENSOR_VALUE_TYPE_HERTZ = 7;

+    SENSOR_VALUE_TYPE_CELSIUS = 8;

+    SENSOR_VALUE_TYPE_PERCENT_RH = 9;

+    SENSOR_VALUE_TYPE_RPM = 10;

+    SENSOR_VALUE_TYPE_CMM = 11;

+    SENSOR_VALUE_TYPE_TRUTH_VALUE = 12;

+}

+

+enum SensorValueScale {

+    SENSOR_VALUE_SCALE_UNDEFINED = 0;

+    SENSOR_VALUE_SCALE_YOCTO = 1;

+    SENSOR_VALUE_SCALE_ZEPTO = 2;

+    SENSOR_VALUE_SCALE_ATTO = 3;

+    SENSOR_VALUE_SCALE_FEMTO = 4;

+    SENSOR_VALUE_SCALE_PICO = 5;

+    SENSOR_VALUE_SCALE_NANO = 6;

+    SENSOR_VALUE_SCALE_MICRO = 7;

+    SENSOR_VALUE_SCALE_MILLI = 8;

+    SENSOR_VALUE_SCALE_UNITS = 9;

+    SENSOR_VALUE_SCALE_KILO = 10;

+    SENSOR_VALUE_SCALE_MEGA = 11;

+    SENSOR_VALUE_SCALE_GIGA = 12;

+    SENSOR_VALUE_SCALE_TERA = 13;

+    SENSOR_VALUE_SCALE_PETA = 14;

+    SENSOR_VALUE_SCALE_EXA = 15;

+    SENSOR_VALUE_SCALE_ZETTA = 16;

+    SENSOR_VALUE_SCALE_YOTTA =17;

+}

+

+enum SensorStatus {

+    SENSOR_STATUS_UNDEFINED = 0;

+    SENSOR_STATUS_OK = 1;

+    SENSOR_STATUS_UNAVAILABLE = 2;

+    SENSOR_STATUS_NONOPERATIONAL = 3;

+}

+

+message ComponentSensorData {

+    int32 value = 1;

+    SensorValueType type = 2;

+    SensorValueScale scale = 3;

+    int32 precision = 4;

+    SensorStatus status = 5;

+    string units_display = 6;

+    google.protobuf.Timestamp timestamp = 7;

+    uint32 value_update_rate = 8;

+    // data_type can be of the string representation of MetricNames or something else as well

+    string data_type = 9;

+}

+

+message Component {

+    // The name of a component uniquely identifies an component within the Hardware

+    string name = 1;

+    ComponentType class = 2;

+    string description = 3;

+    Component parent = 4;

+    int32 parent_rel_pos = 5;

+    repeated Component children = 6;

+    string hardware_rev = 7;

+    string firmware_rev = 8;

+    string software_rev = 9;

+    string serial_num = 10;

+    string mfg_name = 11;

+    string model_name = 12;

+    string alias = 13;

+    string asset_id = 14;

+    bool is_fru = 15;

+    google.protobuf.Timestamp mfg_date = 16;

+    Uri uri = 17;

+    // The uuid of the component uniquely identifies the component across the entire system

+    Uuid uuid= 18;

+    ComponentState state = 19;

+    repeated ComponentSensorData sensor_data = 20;

+}

+

+message Hardware {

+    google.protobuf.Timestamp last_change = 1;

+    // Each HW has one parent/root and all other components are children of this

+    // The class of the root component would be set as UNDEFINED

+    Component root = 2;

+    // TODO: Authetication?

+}

+

+// The attributes of a component which are modifiable from the client side

+message ModifiableComponent {

+    // The name has to be unique for each component within the hardware and implementations need to

+    // ascertain this when modifying the name

+    string name = 1;

+    ComponentType class = 2;

+    Component parent = 3;

+    int32 parent_rel_pos = 4;

+    string alias = 5;

+    string asset_id = 6;

+    Uri uri = 7;

+    ComponentAdminState admin_state = 8;

+}

diff --git a/protos/dmi/hw_events_mgmt_service.proto b/protos/dmi/hw_events_mgmt_service.proto
new file mode 100644
index 0000000..6911df3
--- /dev/null
+++ b/protos/dmi/hw_events_mgmt_service.proto
@@ -0,0 +1,137 @@
+syntax = "proto3";

+

+option go_package = "github.com/opencord/device-management-interface/v3/go/dmi";

+package dmi;

+

+import "dmi/commons.proto";

+import "dmi/hw.proto";

+import "google/protobuf/timestamp.proto";

+

+// Management of Events and protos for encoding of Events

+

+enum EventIds {

+    EVENT_NAME_UNDEFINED = 0;

+

+    // Events from the Transceivers

+    EVENT_TRANSCEIVER_PLUG_OUT = 100;

+    EVENT_TRANSCEIVER_PLUG_IN = 101;

+    EVENT_TRANSCEIVER_VOLTAGE_ABOVE_THRESHOLD = 102;

+    EVENT_TRANSCEIVER_VOLTAGE_BELOW_THRESHOLD = 103;

+    EVENT_TRANSCEIVER_TEMPERATURE_ABOVE_THRESHOLD = 104;

+    EVENT_TRANSCEIVER_TEMPERATURE_BELOW_THRESHOLD = 105;

+    EVENT_TRANSCEIVER_CURRENT_ABOVE_THRESHOLD = 106;

+    EVENT_TRANSCEIVER_CURRENT_BELOW_THRESHOLD = 107;

+    EVENT_TRANSCEIVER_RX_POWER_ABOVE_THRESHOLD = 108;

+    EVENT_TRANSCEIVER_RX_POWER_BELOW_THRESHOLD = 109;

+    EVENT_TRANSCEIVER_TX_POWER_ABOVE_THRESHOLD = 110;

+    EVENT_TRANSCEIVER_TX_POWER_BELOW_THRESHOLD = 111;

+    EVENT_TRANSCEIVER_FAILURE = 112;

+

+    // Events from the PSU

+    EVENT_PSU_PLUG_OUT = 200;

+    EVENT_PSU_PLUG_IN = 201;

+    EVENT_PSU_FAILURE = 202;

+

+    // Events for the Fans

+    EVENT_FAN_FAILURE = 300;

+    EVENT_FAN_PLUG_OUT = 301;

+    EVENT_FAN_PLUG_IN = 302;

+

+    // Events for the CPUs

+    EVENT_CPU_TEMPERATURE_ABOVE_CRITICAL = 400;

+    EVENT_CPU_TEMPERATURE_ABOVE_FATAL = 401;

+

+    // Events for the complete HW Device

+    EVENT_HW_DEVICE_RESET = 500;

+    EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL = 501;

+    EVENT_HW_DEVICE_TEMPERATURE_ABOVE_FATAL = 502;

+

+    // More to be added

+}

+

+message ValueType {

+    oneof val{

+        int64 int_val = 1;

+        uint64 uint_val = 2;

+        float float_val = 3;

+    }

+}

+

+message WaterMarks {

+    ValueType high = 1;

+    ValueType low = 2;

+}

+

+message Thresholds {

+    oneof threshold {

+        WaterMarks upper = 1;

+        WaterMarks lower = 2;

+    }

+}

+

+message ThresholdInformation {

+    ValueType observed_value = 1;

+    Thresholds thresholds = 2;

+}

+

+message EventCfg {

+    EventIds event_id = 1;

+    bool is_configured = 2;

+    // Optional threshold values, applicable only for some specific events

+    Thresholds thresholds = 3;

+}

+

+message EventsCfg {

+    repeated EventCfg items = 1;

+}

+

+message ListEventsResponse {

+    Status status = 1;

+    Reason reason = 2;

+    EventsCfg events = 3;

+}

+

+message EventsConfigurationRequest {

+    Uuid device_uuid = 1;

+    oneof operation {

+        EventsCfg changes = 2;

+        bool reset_to_default = 3;

+    }

+}

+

+message EventsConfigurationResponse {

+    Status status = 1;

+    Reason reason = 2;

+}

+

+message EventMetaData {

+    Uuid device_uuid = 1;

+    // uuid of the component

+    Uuid component_uuid = 2;

+    string component_name = 3;

+}

+

+// The Events are conveyed to external systems by submitting them on a kafka bus.

+// The topic to which are Events are submitted would be configured as startup

+// configuration of the components

+

+message Event {

+    EventMetaData event_metadata = 1;

+    EventIds event_id = 2;

+    google.protobuf.Timestamp raised_ts = 3;

+    // Optional threshold information for an event

+    ThresholdInformation threshold_info = 4;

+    // Any additional info regarding the event

+    string add_info = 5;

+}

+

+service NativeEventsManagementService {

+

+    // List the supported events for the passed device

+    rpc ListEvents(HardwareID) returns(ListEventsResponse);

+

+    // Updates the configuration of the list of events in the request

+    // The default behaviour of the device is to report all the supported events

+    // This configuration is persisted across reboots of the device or the device manager

+    rpc UpdateEventsConfiguration(EventsConfigurationRequest) returns(EventsConfigurationResponse);

+}

diff --git a/protos/dmi/hw_management_service.proto b/protos/dmi/hw_management_service.proto
new file mode 100644
index 0000000..5b780e7
--- /dev/null
+++ b/protos/dmi/hw_management_service.proto
@@ -0,0 +1,57 @@
+syntax = "proto3";

+

+option go_package = "github.com/opencord/device-management-interface/v3/go/dmi";

+package dmi;

+

+import "dmi/commons.proto";

+import "dmi/hw.proto";

+

+// Protos for the management of a hardware and it's components

+

+message PhysicalInventoryRequest {

+    Uuid device_uuid = 1;

+}

+

+message PhysicalInventoryResponse {

+    Status status = 1;

+    Reason reason = 2;

+    Hardware inventory = 3;

+}

+

+message HWComponentInfoGetRequest {

+    Uuid device_uuid = 1;

+    Uuid component_uuid = 2;

+    string component_name = 3;

+}

+

+message HWComponentInfoSetRequest {

+    Uuid device_uuid = 1;

+    Uuid component_uuid = 2;

+    string component_name = 3;

+    ModifiableComponent changes = 4;

+}

+

+message HWComponentInfoSetResponse {

+    Status status = 1;

+    Reason reason = 2;

+}

+

+message StartManagingDeviceResponse {

+    Status status = 1;

+    Reason reason = 2;

+    Uuid device_uuid = 3;

+}

+

+service NativeHWManagementService {

+    // Initializes context for a device and sets up required states

+    rpc StartManagingDevice(Hardware) returns(stream StartManagingDeviceResponse);

+

+    // Get the HW inventory details of the Device

+    rpc GetPhysicalInventory(PhysicalInventoryRequest) returns(stream PhysicalInventoryResponse);

+

+    // Get the details of a particular HW component

+    rpc GetHWComponentInfo(HWComponentInfoGetRequest) returns(stream Component);

+

+    // Sets the permissible attributes of a HW component

+    rpc SetHWComponentInfo(HWComponentInfoSetRequest) returns(HWComponentInfoSetResponse);

+}

diff --git a/protos/dmi/hw_metrics_mgmt_service.proto b/protos/dmi/hw_metrics_mgmt_service.proto
new file mode 100644
index 0000000..a30199f
--- /dev/null
+++ b/protos/dmi/hw_metrics_mgmt_service.proto
@@ -0,0 +1,125 @@
+syntax = "proto3";

+

+option go_package = "github.com/opencord/device-management-interface/v3/go/dmi";

+package dmi;

+

+import "dmi/commons.proto";

+import "dmi/hw.proto";

+

+// The model used to represent the event data on the SensorData of a component as described

+// in RFC8348 (https://tools.ietf.org/html/rfc8348)

+

+// Management of Metrics and protos for encoding of Metrics

+

+enum MetricNames {

+    METRIC_NAME_UNDEFINED = 0;

+

+    // FAN related metrics

+    METRIC_FAN_SPEED = 1;

+

+    // CPU related metrics

+    METRIC_CPU_TEMP = 100;

+    METRIC_CPU_USAGE_PERCENTAGE = 101;

+

+    // Transceiver related metrics

+    METRIC_TRANSCEIVER_TEMP = 200;

+    METRIC_TRANSCEIVER_VOLTAGE = 201;

+    METRIC_TRANSCEIVER_BIAS = 202;

+    METRIC_TRANSCEIVER_RX_POWER = 203;

+    METRIC_TRANSCEIVER_TX_POWER = 204;

+    METRIC_TRANSCEIVER_WAVELENGTH = 205;

+

+    // Disk related metrics

+    METRIC_DISK_TEMP = 300;

+    METRIC_DISK_CAPACITY = 301;

+    METRIC_DISK_USAGE = 302;

+    METRIC_DISK_USAGE_PERCENTAGE = 303;

+    METRIC_DISK_READ_WRITE_PERCENTAGE = 304;

+    METRIC_DISK_FAULTY_CELLS_PERCENTAGE = 305;

+

+    // RAM related metrics

+    METRIC_RAM_TEMP = 400;

+    METRIC_RAM_CAPACITY = 401;

+    METRIC_RAM_USAGE = 402;

+    METRIC_RAM_USAGE_PERCENTAGE = 403;

+

+    // Power related metrics

+    METRIC_POWER_MAX = 500;

+    METRIC_POWER_USAGE = 501;

+    METRIC_POWER_USAGE_PERCENTAGE = 502;

+

+    // Chassis related metrics

+    METRIC_INNER_SURROUNDING_TEMP = 600;

+}

+

+message MetricConfig {

+    MetricNames metric_id = 1;

+    // Whether the device manager is collecting and reporting this metric or not

+    bool is_configured = 2;

+    // Number of seconds between two consecutive polls of the particular metric

+    // Each device manager implemenation could have it's per metric default poll frequency which

+    // can be requested to be changed using this value

+    uint32 poll_interval = 3;

+}

+

+message MetricsConfig {

+    repeated MetricConfig metrics = 1;

+}

+

+message ListMetricsResponse {

+    Status status = 1;

+    Reason reason = 2;

+    MetricsConfig metrics = 3;

+}

+

+message MetricsConfigurationRequest {

+    Uuid device_uuid = 1;

+    oneof operation {

+        MetricsConfig changes = 2;

+        bool reset_to_default = 3;

+    }

+}

+

+message MetricsConfigurationResponse {

+    Status status = 1;

+    Reason reason = 2;

+}

+

+message MetricMetaData {

+    Uuid device_uuid = 1;

+    // uuid of the component

+    Uuid component_uuid = 2;

+    string component_name = 3;

+}

+

+// The Metrics are conveyed to external systems by submitting them on a kafka bus.

+// The topic to which are Metrics are submitted would be configured as startup

+// configuration of the components

+message Metric {

+    MetricNames metric_id = 1;

+    MetricMetaData metric_metadata = 2;

+    ComponentSensorData value = 3;

+}

+

+message GetMetricRequest {

+    MetricMetaData meta_data = 1;

+    MetricNames metric_id = 2;

+}

+

+service NativeMetricsManagementService {

+

+    // List the supported metrics for the passed device.

+    // This would be the first call that you make to know about the metrics that a particular device supports and

+    // then use the UpdateMetricsConfiguration API to monitor only the required metrics.

+    rpc ListMetrics(HardwareID) returns(ListMetricsResponse);

+

+    // Updates the configuration of the list of metrics in the request

+    // Acts upon single metric configuration, collection of a single metric can be started/stopped

+    // by changing its configuration.

+    //

+    // This configuration is persisted across restart of the device or the device manager

+    rpc UpdateMetricsConfiguration(MetricsConfigurationRequest) returns(MetricsConfigurationResponse);

+

+    // Get the instantenous value of a metric

+    rpc GetMetric(GetMetricRequest) returns(Metric);

+}

diff --git a/protos/dmi/sw_image.proto b/protos/dmi/sw_image.proto
new file mode 100644
index 0000000..e85767e
--- /dev/null
+++ b/protos/dmi/sw_image.proto
@@ -0,0 +1,53 @@
+syntax = "proto3";

+

+option go_package = "github.com/opencord/device-management-interface/v3/go/dmi";

+package dmi;

+

+import "dmi/commons.proto";

+

+// Protos for modeling a software image and it's status

+

+message ImageVersion {

+    string image_name = 1;

+    string version = 2;

+}

+

+message ImageInformation {

+    ImageVersion image = 1;

+    // Script used by the device specific managers to install the image.

+    // Script must be included in the object downloaded from the image_url

+    string image_install_script = 2;

+    // Location of the image and installation script, authentication (user/pass) if any should be in the url string

+    string image_url = 3;

+    // SHA-256 sum of the image (sha256sum on Linux)

+    string sha256sum = 5;

+}

+

+message ImageStatus {

+    enum ImageState {

+        UNDEFINED_STATE = 0;

+        COPYING_IMAGE = 1;

+        INSTALLING_IMAGE = 2;

+        COMMITING_IMAGE = 3;

+        REBOOTING_DEVICE = 4;

+        UPGRADE_COMPLETE = 5;

+        UPGRADE_FAILED = 6;

+        ACTIVATION_COMPLETE = 7;

+        ACTIVATION_FAILED = 8;

+    }

+

+    enum Reason {

+        UNDEFINED_READON = 0;

+        ERROR_IN_REQUEST = 1;

+        INTERNAL_ERROR = 2;

+        DEVICE_IN_WRONG_STATE = 3;

+        INVALID_IMAGE = 4;

+        WRONG_IMAGE_CHECKSUM = 5;

+    }

+

+    Status status  = 1;

+    Reason reason = 2;

+    ImageState state = 3;

+    // description contains more information about the current state of the procedure and is device dependant

+    string description = 4;

+}

diff --git a/protos/dmi/sw_management_service.proto b/protos/dmi/sw_management_service.proto
new file mode 100644
index 0000000..3a935d0
--- /dev/null
+++ b/protos/dmi/sw_management_service.proto
@@ -0,0 +1,43 @@
+syntax = "proto3";

+

+option go_package = "github.com/opencord/device-management-interface/v3/go/dmi";

+package dmi;

+

+import "dmi/hw.proto";

+import "dmi/sw_image.proto";

+

+// The software management concept described here is aligned with WT-383a3 (Revision: 06 April 2020).

+// In particular Section 11 Software management

+// TODO check model

+

+// Protos for managing the software on a hardware device

+

+message SoftwareVersionInformation {

+    repeated ImageVersion active_versions = 1;

+    repeated ImageVersion standby_versions = 2;

+}

+

+message DownloadImageRequest {

+    Uuid device_uuid = 1;

+    ImageInformation image_info = 2;

+}

+

+service NativeSoftwareManagementService {

+    // Get the software version information of the Active and Standby images

+    rpc GetSoftwareVersion(HardwareID) returns(SoftwareVersionInformation);

+

+    // Downloads and installs the image in the standby partition, returns the status/progress of the Install

+    rpc DownloadImage(DownloadImageRequest) returns(stream ImageStatus);

+

+    // Activates and runs the OLT with the image in the standby partition. If things are fine this image will

+    // henceforth be marked as the Active Partition. The old working image would remain on the Standby partition.

+    // Any possibly required (sub-)steps like "commit" are left to the "Device Manager"

+    rpc ActivateImage(HardwareID) returns(stream ImageStatus);

+

+    // Marks the image in the Standby as Active and reboots the device, so that it boots from that image which was in the standby.

+    // This API is to be used if operator wants to go back to the pervious software

+    rpc RevertToStandbyImage(HardwareID) returns(stream ImageStatus);

+

+    // If needed we can add this later

+    //rpc SubscribeToEvents() returns (stream );

+}