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 );
+}