Adapt pyosaf to support python3, and be compatible with python2
---
 python/pyosaf/saAis.py                | 51 +++++++++++++++++++++++----
 python/pyosaf/saAmf.py                |  8 +++--
 python/pyosaf/saImm.py                |  4 ++-
 python/pyosaf/saLog.py                |  4 ++-
 python/pyosaf/utils/immoi/agent.py    |  2 +-
 python/pyosaf/utils/immom/accessor.py | 10 +++---
 python/pyosaf/utils/immom/agent.py    | 11 +++---
 python/pyosaf/utils/immom/ccb.py      | 19 +++++-----
 python/pyosaf/utils/immom/iterator.py |  9 ++---
 python/pyosaf/utils/immom/object.py   |  2 +-
 python/pyosaf/utils/ntf/producer.py   | 24 +++++++------
 src/imm/tools/immxml-merge            | 32 ++++++++++++-----
 12 files changed, 123 insertions(+), 53 deletions(-)

diff --git a/python/pyosaf/saAis.py b/python/pyosaf/saAis.py
index 178ea554c..912523e69 100644
--- a/python/pyosaf/saAis.py
+++ b/python/pyosaf/saAis.py
@@ -18,13 +18,15 @@
 '''
 Common types and prototypes used by all modules in pyosaf
 '''
+import sys
 from os import environ
-
 import ctypes
 from ctypes import pointer, POINTER, cast, byref, c_void_p, Structure, \
        Union, CDLL
 from pyosaf.saEnumConst import Enumeration, Const
 
+PY3 = True if sys.version_info[0] == 3 else False
+
 SaInt8T = ctypes.c_char
 SaInt16T = ctypes.c_short
 SaInt32T = ctypes.c_int
@@ -39,7 +41,21 @@ SaVoidPtr = c_void_p
 # Types used by the NTF/IMMS service
 SaFloatT = ctypes.c_float
 SaDoubleT = ctypes.c_double
-SaStringT = ctypes.c_char_p
+if PY3:
+       class SaStringT(ctypes.c_char_p):
+               def __init__(self, value=''):
+                       if value is not None:
+                               value = value.encode('utf-8')
+                       super(SaStringT, self).__init__(value)
+
+               def __str__(self):
+                       if self.value is not None:
+                               return self.value.decode('utf-8')
+                       else:
+                               return self.__repr__()
+else:
+       SaStringT = ctypes.c_char_p
+
 
 SaTimeT = SaInt64T
 SaInvocationT = SaUint64T
@@ -177,6 +193,12 @@ if environ.get('SA_ENABLE_EXTENDED_NAMES') == '1':
                        immdll.saAisNameLend.argtypes = [SaConstStringT,
                                                                                
        POINTER(SaNameT)]
                        immdll.saAisNameLend.restype = None
+                       if PY3:
+                               # Add name_in_bytes attribute to this object as 
a workaround
+                               # To keep the `name` in bytes not to be freed 
by garbarge
+                               # collector when it's still refered in 
`_opaque` of SaNameT
+                               self.name_in_bytes = name.encode('utf-8')
+                               name = self.name_in_bytes
 
                        immdll.saAisNameLend(name, BYREF(self))
 
@@ -185,7 +207,11 @@ if environ.get('SA_ENABLE_EXTENDED_NAMES') == '1':
                        """
                        immdll.saAisNameBorrow.argtypes = [POINTER(SaNameT)]
                        immdll.saAisNameBorrow.restype = SaConstStringT
-                       return immdll.saAisNameBorrow(BYREF(self))
+                       name = immdll.saAisNameBorrow(BYREF(self))
+                       if PY3:
+                               return name.decode('utf-8')
+
+                       return name
 else:
        class SaNameT(Structure):
                """Contain names.
@@ -196,12 +222,17 @@ else:
                def __init__(self, name=''):
                        """Construct instance with contents of 'name'.
                        """
+                       if PY3:
+                               name = name.encode('utf-8')
                        super(SaNameT, self).__init__(len(name), name)
 
                def __str__(self):
                        """Returns the content of SaNameT
                        """
-                       return self.value
+                       if PY3:
+                               return self.value.decode('utf-8')
+                       else:
+                               return self.value
 
 
 class SaVersionT(Structure):
@@ -211,6 +242,14 @@ class SaVersionT(Structure):
                ('majorVersion', SaUint8T),
                ('minorVersion', SaUint8T)]
 
+       def __init__(self, release='_', major=0, minor=0):
+               """Construct instance with contents of 'name'.
+               """
+               if PY3:
+                       release = release[0].encode('utf-8')
+
+               super(SaVersionT, self).__init__(release, major, minor)
+
 
 class SaLimitValueT(Union):
        """Contain the value of an implementation-specific limit.
@@ -259,7 +298,7 @@ def unmarshalNullArray(c_array):
        if not c_array:
                return []
        ctype = c_array[0].__class__
-       if ctype is str:
+       if ctype is str or (PY3 and ctype is SaStringT):
                return unmarshalSaStringTArray(c_array)
        val_list = []
        for ptr in c_array:
@@ -278,7 +317,7 @@ def unmarshalSaStringTArray(c_array):
        for ptr in c_array:
                if not ptr:
                        break
-               val_list.append(ptr)
+               val_list.append(str(ptr))
        return val_list
 
 
diff --git a/python/pyosaf/saAmf.py b/python/pyosaf/saAmf.py
index 5d2fca628..ff9265d22 100644
--- a/python/pyosaf/saAmf.py
+++ b/python/pyosaf/saAmf.py
@@ -19,7 +19,7 @@ from ctypes import POINTER, Structure, CFUNCTYPE, CDLL, Union
 from pyosaf.saAis import SaAisErrorT, SaInvocationT, SaNameT, SaUint64T, \
         SaUint32T, SaTimeT, SaUint8T, SaInt64T, SaInt32T, SaDispatchFlagsT, \
         SaVersionT, SaSelectionObjectT, SaEnumT, Enumeration, SaInt8T, \
-        SaUint16T, Const, BYREF
+        SaUint16T, Const, BYREF, PY3
 from pyosaf.saNtf import SaNtfIdentifierT, SaNtfCorrelationIdsT
 
 # Only mirrors API calls implemented in osaf/libs/agents/saf/ava/ava_api.c
@@ -61,7 +61,11 @@ class SaAmfHealthcheckKeyT(Structure):
        def __init__(self, key=''):
                """Construct instance with contents of 'key'.
                """
-               super(SaAmfHealthcheckKeyT, self).__init__(key, len(key))
+               if PY3:
+                       key = key.encode('utf-8')
+                       super(SaAmfHealthcheckKeyT, self).__init__(key, 
len(key))
+               else:
+                       super(SaAmfHealthcheckKeyT, self).__init__(key, 
len(key))
 
 SaAmfHAStateT = SaEnumT
 eSaAmfHAStateT = Enumeration((
diff --git a/python/pyosaf/saImm.py b/python/pyosaf/saImm.py
index e464dc17e..f167a4e4f 100644
--- a/python/pyosaf/saImm.py
+++ b/python/pyosaf/saImm.py
@@ -24,7 +24,7 @@ from ctypes import cast, pointer, POINTER, Structure, Union
 from pyosaf.saAis import SaStringT, SaEnumT, SaInt32T, SaUint32T, SaInt64T, \
     SaUint64T, SaTimeT, SaNameT, SaFloatT, SaDoubleT, SaStringT, SaAnyT
 from pyosaf.saEnumConst import Enumeration, Const
-from pyosaf.saAis import SaVoidPtr
+from pyosaf.saAis import SaVoidPtr, PY3
 
 saImm = Const()
 
@@ -72,6 +72,8 @@ def unmarshalSaImmValue(void_ptr, value_type):
        if val_ptr and void_ptr:
                if val_ptr == SaNameT:
                        return str(cast(void_ptr, POINTER(val_ptr))[0])
+               elif val_ptr == SaStringT and PY3:
+                       return str(cast(void_ptr, POINTER(val_ptr))[0])
                return cast(void_ptr, POINTER(val_ptr))[0]
        return None
 
diff --git a/python/pyosaf/saLog.py b/python/pyosaf/saLog.py
index ad24b219b..039a47d4a 100644
--- a/python/pyosaf/saLog.py
+++ b/python/pyosaf/saLog.py
@@ -20,7 +20,7 @@ from ctypes import POINTER, CDLL, Structure, CFUNCTYPE, 
create_string_buffer, \
 from pyosaf.saAis import SaUint64T, Const, SaUint16T, SaVersionT, SaStringT, \
         SaUint32T, SaBoolT, SaEnumT, Enumeration, SaInvocationT, SaAisErrorT, \
         BYREF, SaDispatchFlagsT, SaNameT, SaTimeT, SaSelectionObjectT, \
-        SaUint8T, SaSizeT, SaInt8T, SaLimitValueT
+        SaUint8T, SaSizeT, SaInt8T, SaLimitValueT, PY3
 from pyosaf import saNtf
 
 # Only mirrors API calls implemented in osaf/libs/agents/saf/lga/lga_api.c
@@ -66,6 +66,8 @@ class SaLogBufferT(Structure):
        _fields_ = [('logBufSize', SaSizeT),
                ('logBuf', POINTER(SaInt8T))]
        def __init__(self, buf=''):
+               if PY3:
+                       buf = buf.encode('utf-8')
                super(SaLogBufferT, self).__init__(len(buf),
                        create_string_buffer(buf) if buf else None)
 
diff --git a/python/pyosaf/utils/immoi/agent.py 
b/python/pyosaf/utils/immoi/agent.py
index 74bd1330d..e0697b1ef 100644
--- a/python/pyosaf/utils/immoi/agent.py
+++ b/python/pyosaf/utils/immoi/agent.py
@@ -356,7 +356,7 @@ class OiAgent(object):
         """
         _, class_desc = self.imm_om.get_class_description(class_name)
         attr_desc = [attr for attr in class_desc if
-                     attr.attrName == attribute][0]
+                     str(attr.attrName) == attribute][0]
 
         return attr_desc.attrValueType
 
diff --git a/python/pyosaf/utils/immom/accessor.py 
b/python/pyosaf/utils/immom/accessor.py
index bed08d5fa..93ed84c85 100644
--- a/python/pyosaf/utils/immom/accessor.py
+++ b/python/pyosaf/utils/immom/accessor.py
@@ -121,11 +121,11 @@ class ImmOmAccessor(agent.OmAgentManager):
             attr_list = unmarshalNullArray(attributes)
             for attr in attr_list:
                 attr_range = list(range(attr.attrValuesNumber))
-                attrs[attr.attrName] = [attr.attrValueType,
-                                        [unmarshalSaImmValue(
-                                            attr.attrValues[val],
-                                            attr.attrValueType)
-                                         for val in attr_range]]
+                attrs[str(attr.attrName)] = [
+                    attr.attrValueType,
+                    [unmarshalSaImmValue(attr.attrValues[val],
+                                         attr.attrValueType)
+                     for val in attr_range]]
             if 'SaImmAttrClassName' not in attrs and class_name:
                 attrs['SaImmAttrClassName'] = class_name
             imm_obj = ImmObject(dn=object_name, attributes=attrs)
diff --git a/python/pyosaf/utils/immom/agent.py 
b/python/pyosaf/utils/immom/agent.py
index dc91fc6ea..0413f1bd1 100644
--- a/python/pyosaf/utils/immom/agent.py
+++ b/python/pyosaf/utils/immom/agent.py
@@ -23,7 +23,7 @@ from ctypes import pointer
 from pyosaf import saImmOm, saImm
 from pyosaf.saAis import saAis, SaVersionT, SaNameT, SaAisErrorT, \
     eSaAisErrorT, eSaBoolT, unmarshalNullArray
-from pyosaf.saImm import eSaImmScopeT
+from pyosaf.saImm import eSaImmScopeT, SaImmClassNameT, SaImmAttrNameT
 from pyosaf.utils import decorate, initialize_decorate, log_err
 
 # Decorate pure saImmOm* API's with error-handling retry and exception raising
@@ -211,7 +211,8 @@ class ImmOmAgent(OmAgentManager):
         def attr_def_copy(attr_def):
             """ Deep copy attributes """
             attr_def_cpy = saImm.SaImmAttrDefinitionT_2()
-            attr_def_cpy.attrName = attr_def.attrName[:]
+            attr_def_cpy.attrName = SaImmAttrNameT(
+                deepcopy(str(attr_def.attrName)))
             attr_def_cpy.attrValueType = attr_def.attrValueType
             attr_def_cpy.attrFlags = attr_def.attrFlags
 
@@ -220,7 +221,9 @@ class ImmOmAgent(OmAgentManager):
         class_attrs = []
         attr_defs = pointer(pointer(saImm.SaImmAttrDefinitionT_2()))
         category = saImm.SaImmClassCategoryT()
-        rc = saImmOmClassDescriptionGet_2(self.handle, class_name, category,
+        rc = saImmOmClassDescriptionGet_2(self.handle,
+                                          SaImmClassNameT(class_name),
+                                          category,
                                           attr_defs)
         if rc != eSaAisErrorT.SA_AIS_OK:
             log_err("saImmOmClassDescriptionGet_2 FAILED - %s" %
@@ -253,7 +256,7 @@ class ImmOmAgent(OmAgentManager):
         else:
             for attr_desc in class_attrs:
                 if attr_desc.attrFlags & saImm.saImm.SA_IMM_ATTR_RDN:
-                    return attr_desc.attrName
+                    return str(attr_desc.attrName)
 
     def invoke_admin_operation(self, dn, op_id, params=None):
         """ Invoke admin op for dn
diff --git a/python/pyosaf/utils/immom/ccb.py b/python/pyosaf/utils/immom/ccb.py
index 8edd526b1..a23f777d3 100644
--- a/python/pyosaf/utils/immom/ccb.py
+++ b/python/pyosaf/utils/immom/ccb.py
@@ -22,7 +22,8 @@ from ctypes import c_void_p, pointer, cast, POINTER
 from pyosaf.saAis import eSaAisErrorT, SaNameT, SaStringT, SaFloatT, \
     unmarshalNullArray, SaDoubleT, SaTimeT, SaUint64T, SaInt64T, SaUint32T, \
     SaInt32T
-from pyosaf.saImm import eSaImmScopeT, eSaImmValueTypeT, SaImmAttrValuesT_2
+from pyosaf.saImm import eSaImmScopeT, eSaImmValueTypeT, SaImmAttrValuesT_2, \
+    SaImmAttrNameT, SaImmClassNameT
 from pyosaf import saImm
 from pyosaf import saImmOm
 from pyosaf.utils.immom import agent
@@ -44,13 +45,13 @@ def _value_to_ctype_ptr(value_type, value):
     if value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAINT32T:
         ctypeptr = cast(pointer(SaInt32T(value)), c_void_p)
     elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAUINT32T:
-        ctypeptr = cast(pointer(SaUint32T(long(value))), c_void_p)
+        ctypeptr = cast(pointer(SaUint32T(value)), c_void_p)
     elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAINT64T:
-        ctypeptr = cast(pointer(SaInt64T(long(value))), c_void_p)
+        ctypeptr = cast(pointer(SaInt64T(value)), c_void_p)
     elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAUINT64T:
-        ctypeptr = cast(pointer(SaUint64T(long(value))), c_void_p)
+        ctypeptr = cast(pointer(SaUint64T(value)), c_void_p)
     elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SATIMET:
-        ctypeptr = cast(pointer(SaTimeT(long(value))), c_void_p)
+        ctypeptr = cast(pointer(SaTimeT(value)), c_void_p)
     elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SANAMET:
         ctypeptr = cast(pointer(SaNameT(value)), c_void_p)
     elif value_type is eSaImmValueTypeT.SA_IMM_ATTR_SAFLOATT:
@@ -172,7 +173,7 @@ class Ccb(ImmOmAgent):
             for attr_name, type_values in obj.attrs.items():
                 values = type_values[1]
                 attr = SaImmAttrValuesT_2()
-                attr.attrName = attr_name
+                attr.attrName = SaImmAttrNameT(attr_name)
                 attr.attrValueType = type_values[0]
 
                 attr.attrValuesNumber = len(values)
@@ -180,7 +181,7 @@ class Ccb(ImmOmAgent):
                 attr_values.append(attr)
 
             rc = agent.saImmOmCcbObjectCreate_2(self.ccb_handle,
-                                                obj.class_name,
+                                                
SaImmClassNameT(obj.class_name),
                                                 parent_name,
                                                 attr_values)
             if rc != eSaAisErrorT.SA_AIS_OK:
@@ -255,7 +256,7 @@ class Ccb(ImmOmAgent):
                 _, attr_def_list = self.get_class_description(class_name)
                 value_type = None
                 for attr_def in attr_def_list:
-                    if attr_def.attrName == attr_name:
+                    if str(attr_def.attrName) == attr_name:
                         value_type = attr_def.attrValueType
                         break
                 if value_type:
@@ -271,7 +272,7 @@ class Ccb(ImmOmAgent):
                 attr_mod = saImmOm.SaImmAttrModificationT_2()
                 attr_mod.modType = mod_type
                 attr_mod.modAttr = SaImmAttrValuesT_2()
-                attr_mod.modAttr.attrName = attr_name
+                attr_mod.modAttr.attrName = SaImmAttrNameT(attr_name)
                 attr_mod.modAttr.attrValueType = value_type
                 attr_mod.modAttr.attrValuesNumber = len(values)
                 attr_mod.modAttr.attrValues = marshal_c_array(value_type,
diff --git a/python/pyosaf/utils/immom/iterator.py 
b/python/pyosaf/utils/immom/iterator.py
index 7402c9427..91c5751c0 100644
--- a/python/pyosaf/utils/immom/iterator.py
+++ b/python/pyosaf/utils/immom/iterator.py
@@ -105,10 +105,11 @@ class SearchIterator(agent.OmAgentManager, Iterator):
         attr_list = unmarshalNullArray(attributes)
         for attr in attr_list:
             attr_range = list(range(attr.attrValuesNumber))
-            attrs[attr.attrName] = [attr.attrValueType,
-                                    [unmarshalSaImmValue(attr.attrValues[val],
-                                                         attr.attrValueType)
-                                     for val in attr_range]]
+            attrs[str(attr.attrName)] = [
+                attr.attrValueType,
+                [unmarshalSaImmValue(attr.attrValues[val],
+                                     attr.attrValueType)
+                 for val in attr_range]]
         return ImmObject(str(obj_name), attrs)
 
     @bad_handle_retry
diff --git a/python/pyosaf/utils/immom/object.py 
b/python/pyosaf/utils/immom/object.py
index 0cef920cc..6e80abfae 100644
--- a/python/pyosaf/utils/immom/object.py
+++ b/python/pyosaf/utils/immom/object.py
@@ -82,7 +82,7 @@ class ImmObject(object):
             SaImmAttrNameT: Attribute value type
         """
         for attr_def in self.class_desc[self.class_name]:
-            if attr_def.attrName == attr_name:
+            if str(attr_def.attrName) == attr_name:
                 return attr_def.attrValueType
 
     def __attr_is_multi_value(self, attr_name):
diff --git a/python/pyosaf/utils/ntf/producer.py 
b/python/pyosaf/utils/ntf/producer.py
index 1d5422536..b9a0ebf9e 100644
--- a/python/pyosaf/utils/ntf/producer.py
+++ b/python/pyosaf/utils/ntf/producer.py
@@ -19,7 +19,8 @@
 import ctypes
 
 from pyosaf import saNtf
-from pyosaf.saAis import eSaBoolT, eSaAisErrorT, SaVoidPtr
+from pyosaf.saNtf import eSaNtfValueTypeT
+from pyosaf.saAis import eSaBoolT, eSaAisErrorT, SaVoidPtr, SaNameT, PY3
 from pyosaf.utils import log_warn, log_err, bad_handle_retry
 from pyosaf.utils.ntf import agent as ntf
 
@@ -87,6 +88,8 @@ class NtfProducer(ntf.NtfAgent):
         elif value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_LDAP_NAME \
                 or value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_STRING \
                 or value_type == saNtf.eSaNtfValueTypeT.SA_NTF_VALUE_IPADDRESS:
+            if PY3:
+                value = value.encode('utf-8')
             len_value = len(value)
             dest_ptr = SaVoidPtr()
             rc = ntf.saNtfPtrValAllocate(ntf_handle, len_value + 1, dest_ptr,
@@ -300,14 +303,10 @@ class NtfProducer(ntf.NtfAgent):
         """
         header.eventType.contents.value = self.ntf_info.event_type
 
-        header.notificationObject.contents.value = \
-            self.ntf_info.notification_object
-        header.notificationObject.contents.length = \
-            len(self.ntf_info.notification_object)
+        header.notificationObject[0] = \
+            SaNameT(self.ntf_info.notification_object)
 
-        header.notifyingObject.contents.value = self.ntf_info.notifying_object
-        header.notifyingObject.contents.length = \
-            len(self.ntf_info.notifying_object)
+        header.notifyingObject[0] = SaNameT(self.ntf_info.notifying_object)
 
         header.notificationClassId.contents.vendorId = \
             self.ntf_info.ntf_class_id.vendorId
@@ -318,10 +317,13 @@ class NtfProducer(ntf.NtfAgent):
 
         header.eventTime.contents.value = self.ntf_info.event_time
 
-        header.lengthAdditionalText = len(self.ntf_info.additional_text)
+        additional_text = self.ntf_info.additional_text
+        if PY3:
+            additional_text = self.ntf_info.additional_text.encode('utf-8')
+        header.lengthAdditionalText = len(additional_text)
         ctypes.memmove(header.additionalText,
-                       self.ntf_info.additional_text,
-                       len(self.ntf_info.additional_text) + 1)
+                       additional_text,
+                       len(additional_text) + 1)
 
         if self.ntf_info.additional_info:
             for i, add_info in enumerate(self.ntf_info.additional_info):
diff --git a/src/imm/tools/immxml-merge b/src/imm/tools/immxml-merge
index 3a9edda9b..9a03d3a9b 100755
--- a/src/imm/tools/immxml-merge
+++ b/src/imm/tools/immxml-merge
@@ -28,9 +28,19 @@ from datetime import datetime
 from baseimm import BaseOptions, BaseImmDocument, trace, retrieve_file_names, \
     print_info_stderr, abort_script, verify_input_file_read_access
 
+PY3 = True if sys.version_info[0] == 3 else False
+
+
+def bytes_to_str(bytes_obj, encoding):
+    """ Convert bytes object to string in python3 """
+    if PY3 and isinstance(bytes_obj, bytes):
+        return bytes_obj.decode(encoding)
+
+    return bytes_obj
+
 
 class Options(BaseOptions):
-    """ immxml-merge options"""
+    """ immxml-merge options """
     keepCommentElements = False
     ignoreVariants = False
     ignoreMissingClass = False
@@ -366,19 +376,25 @@ class MergedImmDocument(BaseImmDocument):
             heading = "<?xml version=\"1.0\"?>"
 
         file_object.write(heading)
-        file_object.write(
-            self.imm_content_element.toxml(encoding).replace("/>", ">") + "\n")
+        string = bytes_to_str(self.imm_content_element.toxml(encoding),
+                              encoding)
+        file_object.write(string.replace("/>", ">") + "\n")
         for class_element_tuple in self.classList:
             if Options.keepCommentElements:
                 for textNode in class_element_tuple[1][0]:
-                    file_object.write(textNode.toxml(encoding) + "\n")
-            file_object.write(class_element_tuple[1][1].toxml(encoding) + "\n")
+                    string = bytes_to_str(textNode.toxml(encoding), encoding)
+                    file_object.write(string + "\n")
+            string = bytes_to_str(class_element_tuple[1][1].toxml(encoding),
+                                  encoding)
+            file_object.write(string + "\n")
         for object_element_tuple in self.objectList:
             if Options.keepCommentElements:
                 for textNode in object_element_tuple[1][0]:
-                    file_object.write(textNode.toxml(encoding) + "\n")
-            file_object.write(
-                object_element_tuple[1][1].toxml(encoding) + "\n")
+                    string = bytes_to_str(textNode.toxml(encoding), encoding)
+                    file_object.write(string + "\n")
+            string = bytes_to_str(object_element_tuple[1][1].toxml(encoding),
+                                  encoding)
+            file_object.write(string + "\n")
         file_object.write("</imm:IMM-contents>")
         file_object.close()
         trace("Stored resulting xml document in tmp file: %s",
-- 
2.17.1



_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to