Commit ae7c1dec authored by Pavel Vainerman's avatar Pavel Vainerman

Рефакторинг: getChangedTime() --> getTimeChange(),

а также добавил эту функцию в python интерфейс.
parent e921bab4
...@@ -144,7 +144,7 @@ interface IOController_i : UniSetManager_i ...@@ -144,7 +144,7 @@ interface IOController_i : UniSetManager_i
uniset::ObjectId supplier; /*!< идентификатор того, кто менял датчик (последний раз) */ uniset::ObjectId supplier; /*!< идентификатор того, кто менял датчик (последний раз) */
}; };
ShortIOInfo getChangedTime( in uniset::ObjectId sid ) raises(NameNotFound); ShortIOInfo getTimeChange( in uniset::ObjectId sid ) raises(NameNotFound);
/*! Информация о дискретном датчике */ /*! Информация о дискретном датчике */
......
...@@ -49,7 +49,7 @@ static struct option longopts[] = ...@@ -49,7 +49,7 @@ static struct option longopts[] =
{ "getValue", required_argument, 0, 'g' }, { "getValue", required_argument, 0, 'g' },
{ "getRawValue", required_argument, 0, 'w' }, { "getRawValue", required_argument, 0, 'w' },
{ "getCalibrate", required_argument, 0, 'y' }, { "getCalibrate", required_argument, 0, 'y' },
{ "getChangedTime", required_argument, 0, 't' }, { "getTimeChange", required_argument, 0, 't' },
{ "oinfo", required_argument, 0, 'p' }, { "oinfo", required_argument, 0, 'p' },
{ "verbose", no_argument, 0, 'v' }, { "verbose", no_argument, 0, 'v' },
{ "quiet", no_argument, 0, 'q' }, { "quiet", no_argument, 0, 'q' },
...@@ -70,7 +70,7 @@ int logRotate( const string& args, UInterface& ui ); ...@@ -70,7 +70,7 @@ int logRotate( const string& args, UInterface& ui );
int setValue( const string& args, UInterface& ui ); int setValue( const string& args, UInterface& ui );
int getValue( const string& args, UInterface& ui ); int getValue( const string& args, UInterface& ui );
int getRawValue( const string& args, UInterface& ui ); int getRawValue( const string& args, UInterface& ui );
int getChangedTime( const string& args, UInterface& ui ); int getTimeChange( const string& args, UInterface& ui );
int getState( const string& args, UInterface& ui ); int getState( const string& args, UInterface& ui );
int getCalibrate( const string& args, UInterface& ui ); int getCalibrate( const string& args, UInterface& ui );
int oinfo(const string& args, UInterface& ui , const string& userparam ); int oinfo(const string& args, UInterface& ui , const string& userparam );
...@@ -116,7 +116,7 @@ static void usage() ...@@ -116,7 +116,7 @@ static void usage()
cout << endl; cout << endl;
print_help(36, "-w|--getRawValue id1@node1,id2@node2,id3,.. ", "Получить 'сырое' значение.\n"); print_help(36, "-w|--getRawValue id1@node1,id2@node2,id3,.. ", "Получить 'сырое' значение.\n");
print_help(36, "-y|--getCalibrate id1@node1,id2@node2,id3,.. ", "Получить параметры калибровки.\n"); print_help(36, "-y|--getCalibrate id1@node1,id2@node2,id3,.. ", "Получить параметры калибровки.\n");
print_help(36, "-t|--getChangedTime id1@node1,id2@node2,id3,.. ", "Получить время последнего изменения.\n"); print_help(36, "-t|--getTimeChange id1@node1,id2@node2,id3,.. ", "Получить время последнего изменения.\n");
print_help(36, "-v|--verbose", "Подробный вывод логов.\n"); print_help(36, "-v|--verbose", "Подробный вывод логов.\n");
print_help(36, "-q|--quiet", "Выводит только результат.\n"); print_help(36, "-q|--quiet", "Выводит только результат.\n");
print_help(36, "-z|--csv", "Вывести результат (getValue) в виде val1,val2,val3...\n"); print_help(36, "-z|--csv", "Вывести результат (getValue) в виде val1,val2,val3...\n");
...@@ -218,13 +218,13 @@ int main(int argc, char** argv) ...@@ -218,13 +218,13 @@ int main(int argc, char** argv)
} }
break; break;
case 't': //--getChangedTime case 't': //--getTimeChange
{ {
auto conf = uniset_init(argc, argv, conffile); auto conf = uniset_init(argc, argv, conffile);
UInterface ui(conf); UInterface ui(conf);
ui.initBackId(uniset::AdminID); ui.initBackId(uniset::AdminID);
string name = ( optarg ) ? optarg : ""; string name = ( optarg ) ? optarg : "";
return getChangedTime(name, ui); return getTimeChange(name, ui);
} }
break; break;
...@@ -843,7 +843,7 @@ int getRawValue( const std::string& args, UInterface& ui ) ...@@ -843,7 +843,7 @@ int getRawValue( const std::string& args, UInterface& ui )
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
int getChangedTime( const std::string& args, UInterface& ui ) int getTimeChange( const std::string& args, UInterface& ui )
{ {
int err = 0; int err = 0;
auto conf = ui.getConf(); auto conf = ui.getConf();
...@@ -863,10 +863,10 @@ int getChangedTime( const std::string& args, UInterface& ui ) ...@@ -863,10 +863,10 @@ int getChangedTime( const std::string& args, UInterface& ui )
{ {
cout << " name: (" << it.si.id << ") " << it.fname << endl; cout << " name: (" << it.si.id << ") " << it.fname << endl;
cout << " text: " << conf->oind->getTextName(it.si.id) << "\n\n"; cout << " text: " << conf->oind->getTextName(it.si.id) << "\n\n";
cout << ui.getChangedTime(it.si.id, it.si.node) << endl; cout << ui.getTimeChange(it.si.id, it.si.node) << endl;
} }
else else
cout << ui.getChangedTime(it.si.id, it.si.node); cout << ui.getTimeChange(it.si.id, it.si.node);
} }
catch( const uniset::Exception& ex ) catch( const uniset::Exception& ex )
{ {
...@@ -1016,7 +1016,7 @@ int oinfo(const string& args, UInterface& ui, const string& userparam ) ...@@ -1016,7 +1016,7 @@ int oinfo(const string& args, UInterface& ui, const string& userparam )
try try
{ {
cout << ui.getInfo(it.id, userparam,it.node) << endl; cout << ui.getObjectInfo(it.id, userparam,it.node) << endl;
} }
catch( const std::exception& ex ) catch( const std::exception& ex )
{ {
......
...@@ -506,6 +506,8 @@ mv -f %buildroot%python_sitelibdir_noarch/* %buildroot%python_sitelibdir/%oname ...@@ -506,6 +506,8 @@ mv -f %buildroot%python_sitelibdir_noarch/* %buildroot%python_sitelibdir/%oname
%exclude %_pkgconfigdir/libUniSet2.pc %exclude %_pkgconfigdir/libUniSet2.pc
# history of current unpublished changes # history of current unpublished changes
- getChangedTime --> getTimeChange
- getInfo( long param ) --> getInfo( string param )
%changelog %changelog
* Tue Nov 22 2016 Pavel Vainerman <pv@altlinux.ru> 2.6-alt3.1 * Tue Nov 22 2016 Pavel Vainerman <pv@altlinux.ru> 2.6-alt3.1
......
...@@ -66,8 +66,8 @@ TEST_CASE("UInterface", "[UInterface]") ...@@ -66,8 +66,8 @@ TEST_CASE("UInterface", "[UInterface]")
si.node = -2; si.node = -2;
REQUIRE_THROWS_AS( ui.setValue(si, 20, DefaultObjectId), uniset::Exception ); REQUIRE_THROWS_AS( ui.setValue(si, 20, DefaultObjectId), uniset::Exception );
REQUIRE_THROWS_AS( ui.getChangedTime(sid, DefaultObjectId), uniset::ORepFailed ); REQUIRE_THROWS_AS( ui.getTimeChange(sid, DefaultObjectId), uniset::ORepFailed );
REQUIRE_NOTHROW( ui.getChangedTime(sid, conf->getLocalNode()) ); REQUIRE_NOTHROW( ui.getTimeChange(sid, conf->getLocalNode()) );
si.id = aid; si.id = aid;
si.node = conf->getLocalNode(); si.node = conf->getLocalNode();
......
...@@ -92,7 +92,7 @@ class IOController: ...@@ -92,7 +92,7 @@ class IOController:
uniset::Message::Priority getPriority( const uniset::ObjectId id ); uniset::Message::Priority getPriority( const uniset::ObjectId id );
virtual IOController_i::ShortIOInfo getChangedTime( const uniset::ObjectId id ) override; virtual IOController_i::ShortIOInfo getTimeChange( const uniset::ObjectId id ) override;
virtual IOController_i::ShortMapSeq* getSensors() override; virtual IOController_i::ShortMapSeq* getSensors() override;
......
...@@ -139,10 +139,10 @@ class UInterface ...@@ -139,10 +139,10 @@ class UInterface
uniset::ObjectType getType(const uniset::ObjectId id) const; uniset::ObjectType getType(const uniset::ObjectId id) const;
//! Время последнего изменения датчика //! Время последнего изменения датчика
IOController_i::ShortIOInfo getChangedTime( const uniset::ObjectId id, const uniset::ObjectId node ) const; IOController_i::ShortIOInfo getTimeChange( const uniset::ObjectId id, const uniset::ObjectId node ) const;
//! Информация об объекте //! Информация об объекте
std::string getInfo( const uniset::ObjectId id, const std::string& params, const uniset::ObjectId node ) const; std::string getObjectInfo( const uniset::ObjectId id, const std::string& params, const uniset::ObjectId node ) const;
//! Получить список датчиков //! Получить список датчиков
IOController_i::ShortMapSeq* getSensors( const uniset::ObjectId id, IOController_i::ShortMapSeq* getSensors( const uniset::ObjectId id,
......
...@@ -175,9 +175,20 @@ class UInterface(): ...@@ -175,9 +175,20 @@ class UInterface():
raise UValidateError("(getObjectID): Unknown interface %s"%self.itype) raise UValidateError("(getObjectID): Unknown interface %s"%self.itype)
def getObjectInfo( self, id, params = "", node = DefaultID ): '''\param o_name - name, id, name@node, id@node'''
def getObjectInfo( self, o_name, params = "" ):
if self.itype != "uniset": if self.itype != "uniset":
raise UException("(getObjectInfo): the interface does not support this feature..'getObjectInfo'") raise UException("(getObjectInfo): the interface does not support this feature..")
return self.i.getObjectInfo( id, params, node ) s = to_sid(o_name,self.i)
return self.i.getObjectInfo( s[0], params, s[1] )
'''\param o_name - name, id, name@node, id@node '''
def getTimeChange( self, o_name ):
if self.itype != "uniset":
raise UException("(getTimeChange): the interface does not support this feature..")
s = to_sid(o_name,self.i)
return self.i.getTimeChange( s[0], s[1] )
\ No newline at end of file
...@@ -114,7 +114,37 @@ void UConnector::setValue( long id, long val, long node, long supplier )throw(UE ...@@ -114,7 +114,37 @@ void UConnector::setValue( long id, long val, long node, long supplier )throw(UE
} }
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
long UConnector::getSensorID(const string& name ) static UTypes::ShortIOInfo toUTypes( IOController_i::ShortIOInfo i )
{
UTypes::ShortIOInfo ret;
ret.value = i.value;
ret.tv_sec = i.tv_sec;
ret.tv_nsec = i.tv_nsec;
ret.supplier = i.supplier;
return std::move(ret);
}
//---------------------------------------------------------------------------
UTypes::ShortIOInfo UConnector::getTimeChange( long id, long node )
{
if( !conf || !ui )
throw USysError();
if( node == UTypes::DefaultID )
node = conf->getLocalNode();
try
{
IOController_i::ShortIOInfo i = ui->getTimeChange(id,node);
return toUTypes(i);
}
catch( const std::exception& ex )
{
throw UException("(getChangedTime): catch " + std::string(ex.what()) );
}
}
//---------------------------------------------------------------------------
long UConnector::getSensorID( const string& name )
{ {
if( conf ) if( conf )
return conf->getSensorID(name); return conf->getSensorID(name);
...@@ -168,7 +198,7 @@ throw(UException) ...@@ -168,7 +198,7 @@ throw(UException)
try try
{ {
return ui->getInfo(id,params,node); return ui->getObjectInfo(id,params,node);
} }
catch( std::exception& ex ) catch( std::exception& ex )
{ {
......
...@@ -40,6 +40,7 @@ class UConnector ...@@ -40,6 +40,7 @@ class UConnector
std::string getConfFileName(); std::string getConfFileName();
long getValue( long id, long node )throw(UException); long getValue( long id, long node )throw(UException);
void setValue( long id, long val, long node, long supplier = UTypes::DefaultSupplerID )throw(UException); void setValue( long id, long val, long node, long supplier = UTypes::DefaultSupplerID )throw(UException);
UTypes::ShortIOInfo getTimeChange( long id, long node = UTypes::DefaultID );
long getSensorID( const std::string& name ); long getSensorID( const std::string& name );
long getNodeID( const std::string& name ); long getNodeID( const std::string& name );
......
...@@ -65,7 +65,16 @@ namespace UTypes ...@@ -65,7 +65,16 @@ namespace UTypes
return Params(); return Params();
} }
}; };
struct ShortIOInfo
{
long value;
unsigned long tv_sec;
unsigned long tv_nsec;
long supplier;
};
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#endif #endif
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
...@@ -110,6 +110,32 @@ def Params_inst(): ...@@ -110,6 +110,32 @@ def Params_inst():
return _pyUConnector.Params_inst() return _pyUConnector.Params_inst()
Params_inst = _pyUConnector.Params_inst Params_inst = _pyUConnector.Params_inst
class ShortIOInfo:
__swig_setmethods__ = {}
__setattr__ = lambda self, name, value: _swig_setattr(self, ShortIOInfo, name, value)
__swig_getmethods__ = {}
__getattr__ = lambda self, name: _swig_getattr(self, ShortIOInfo, name)
__repr__ = _swig_repr
__swig_setmethods__["value"] = _pyUConnector.ShortIOInfo_value_set
__swig_getmethods__["value"] = _pyUConnector.ShortIOInfo_value_get
__swig_setmethods__["tv_sec"] = _pyUConnector.ShortIOInfo_tv_sec_set
__swig_getmethods__["tv_sec"] = _pyUConnector.ShortIOInfo_tv_sec_get
__swig_setmethods__["tv_nsec"] = _pyUConnector.ShortIOInfo_tv_nsec_set
__swig_getmethods__["tv_nsec"] = _pyUConnector.ShortIOInfo_tv_nsec_get
__swig_setmethods__["supplier"] = _pyUConnector.ShortIOInfo_supplier_set
__swig_getmethods__["supplier"] = _pyUConnector.ShortIOInfo_supplier_get
def __init__(self):
this = _pyUConnector.new_ShortIOInfo()
try:
self.this.append(this)
except Exception:
self.this = this
__swig_destroy__ = _pyUConnector.delete_ShortIOInfo
__del__ = lambda self: None
ShortIOInfo_swigregister = _pyUConnector.ShortIOInfo_swigregister
ShortIOInfo_swigregister(ShortIOInfo)
class UConnector: class UConnector:
__swig_setmethods__ = {} __swig_setmethods__ = {}
__setattr__ = lambda self, name, value: _swig_setattr(self, UConnector, name, value) __setattr__ = lambda self, name, value: _swig_setattr(self, UConnector, name, value)
...@@ -138,6 +164,9 @@ class UConnector: ...@@ -138,6 +164,9 @@ class UConnector:
def setValue(self, *args): def setValue(self, *args):
return _pyUConnector.UConnector_setValue(self, *args) return _pyUConnector.UConnector_setValue(self, *args)
def getTimeChange(self, *args):
return _pyUConnector.UConnector_getTimeChange(self, *args)
def getSensorID(self, name): def getSensorID(self, name):
return _pyUConnector.UConnector_getSensorID(self, name) return _pyUConnector.UConnector_getSensorID(self, name)
......
...@@ -48,6 +48,9 @@ if __name__ == "__main__": ...@@ -48,6 +48,9 @@ if __name__ == "__main__":
#obj2 = UProxyObject("TestProc1") #obj2 = UProxyObject("TestProc1")
print "Info: %s"%uc1.getObjectInfo( uc1.getObjectID("TestProc1"),"") print "Info: %s"%uc1.getObjectInfo( uc1.getObjectID("TestProc1"),"")
# tc = uc1.getTimeChange(2)
# print "TimeChange: %s sup=%d"%(tc.value,tc.supplier)
# print "(0)UIType: %s" % uc1.getUIType() # print "(0)UIType: %s" % uc1.getUIType()
print "(1)getShortName: id=%d name=%s" % (1, uc1.getShortName(1)) print "(1)getShortName: id=%d name=%s" % (1, uc1.getShortName(1))
......
...@@ -1027,15 +1027,15 @@ void UInterface::send( const uniset::ObjectId name, const uniset::TransportMessa ...@@ -1027,15 +1027,15 @@ void UInterface::send( const uniset::ObjectId name, const uniset::TransportMessa
} }
// ------------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------------
IOController_i::ShortIOInfo UInterface::getChangedTime( const uniset::ObjectId id, const uniset::ObjectId node ) const IOController_i::ShortIOInfo UInterface::getTimeChange( const uniset::ObjectId id, const uniset::ObjectId node ) const
{ {
if( id == uniset::DefaultObjectId ) if( id == uniset::DefaultObjectId )
throw uniset::ORepFailed("UI(getChangedTime): Unknown id=uniset::DefaultObjectId"); throw uniset::ORepFailed("UI(getTimeChange): Unknown id=uniset::DefaultObjectId");
if( node == uniset::DefaultObjectId ) if( node == uniset::DefaultObjectId )
{ {
ostringstream err; ostringstream err;
err << "UI(getChangedTime): id='" << id << "' error: node=uniset::DefaultObjectId"; err << "UI(getTimeChange): id='" << id << "' error: node=uniset::DefaultObjectId";
throw uniset::ORepFailed(err.str()); throw uniset::ORepFailed(err.str());
} }
...@@ -1057,7 +1057,7 @@ IOController_i::ShortIOInfo UInterface::getChangedTime( const uniset::ObjectId i ...@@ -1057,7 +1057,7 @@ IOController_i::ShortIOInfo UInterface::getChangedTime( const uniset::ObjectId i
oref = resolve( id, node ); oref = resolve( id, node );
IOController_i_var iom = IOController_i::_narrow(oref); IOController_i_var iom = IOController_i::_narrow(oref);
return iom->getChangedTime(id); return iom->getTimeChange(id);
} }
catch( const CORBA::TRANSIENT& ) {} catch( const CORBA::TRANSIENT& ) {}
catch( const CORBA::OBJECT_NOT_EXIST& ) {} catch( const CORBA::OBJECT_NOT_EXIST& ) {}
...@@ -1071,27 +1071,27 @@ IOController_i::ShortIOInfo UInterface::getChangedTime( const uniset::ObjectId i ...@@ -1071,27 +1071,27 @@ IOController_i::ShortIOInfo UInterface::getChangedTime( const uniset::ObjectId i
catch( const IOController_i::NameNotFound& ex) catch( const IOController_i::NameNotFound& ex)
{ {
rcache.erase(id, node); rcache.erase(id, node);
uwarn << "UI(getChangedTime): " << ex.err << endl; uwarn << "UI(getTimeChange): " << ex.err << endl;
} }
catch( const IOController_i::IOBadParam& ex ) catch( const IOController_i::IOBadParam& ex )
{ {
rcache.erase(id, node); rcache.erase(id, node);
throw uniset::IOBadParam("UI(getChangedTime): " + string(ex.err)); throw uniset::IOBadParam("UI(getTimeChange): " + string(ex.err));
} }
catch( const uniset::ORepFailed& ) catch( const uniset::ORepFailed& )
{ {
rcache.erase(id, node); rcache.erase(id, node);
uwarn << set_err("UI(getChangedTime): resolve failed ", id, node) << endl; uwarn << set_err("UI(getTimeChange): resolve failed ", id, node) << endl;
} }
catch( const CORBA::NO_IMPLEMENT& ) catch( const CORBA::NO_IMPLEMENT& )
{ {
rcache.erase(id, node); rcache.erase(id, node);
uwarn << set_err("UI(getChangedTime): method no implement", id, node) << endl; uwarn << set_err("UI(getTimeChange): method no implement", id, node) << endl;
} }
catch( const CORBA::OBJECT_NOT_EXIST& e ) catch( const CORBA::OBJECT_NOT_EXIST& e )
{ {
rcache.erase(id, node); rcache.erase(id, node);
uwarn << set_err("UI(getChangedTime): object not exist", id, node) << endl; uwarn << set_err("UI(getTimeChange): object not exist", id, node) << endl;
} }
catch( const CORBA::COMM_FAILURE& e ) catch( const CORBA::COMM_FAILURE& e )
{ {
...@@ -1105,10 +1105,10 @@ IOController_i::ShortIOInfo UInterface::getChangedTime( const uniset::ObjectId i ...@@ -1105,10 +1105,10 @@ IOController_i::ShortIOInfo UInterface::getChangedTime( const uniset::ObjectId i
} }
rcache.erase(id, node); rcache.erase(id, node);
throw uniset::TimeOut(set_err("UI(getChangedTime): Timeout", id, node)); throw uniset::TimeOut(set_err("UI(getTimeChange): Timeout", id, node));
} }
// ------------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------------
std::string UInterface::getInfo( const ObjectId id, const std::string& params, const ObjectId node ) const std::string UInterface::getObjectInfo( const ObjectId id, const std::string& params, const ObjectId node ) const
{ {
if( id == uniset::DefaultObjectId ) if( id == uniset::DefaultObjectId )
throw uniset::ORepFailed("UI(getInfo): Unknown id=uniset::DefaultObjectId"); throw uniset::ORepFailed("UI(getInfo): Unknown id=uniset::DefaultObjectId");
......
...@@ -707,7 +707,7 @@ IDSeq* IOController::setOutputSeq(const IOController_i::OutSeq& lst, ObjectId su ...@@ -707,7 +707,7 @@ IDSeq* IOController::setOutputSeq(const IOController_i::OutSeq& lst, ObjectId su
return badlist.getIDSeq(); return badlist.getIDSeq();
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
IOController_i::ShortIOInfo IOController::getChangedTime( uniset::ObjectId sid ) IOController_i::ShortIOInfo IOController::getTimeChange( uniset::ObjectId sid )
{ {
auto ait = ioList.find(sid); auto ait = ioList.find(sid);
......
...@@ -41,9 +41,9 @@ TEST_CASE("UInterface", "[UInterface]") ...@@ -41,9 +41,9 @@ TEST_CASE("UInterface", "[UInterface]")
REQUIRE_THROWS_AS( ui.send(testOID, tm), uniset::Exception ); REQUIRE_THROWS_AS( ui.send(testOID, tm), uniset::Exception );
REQUIRE_THROWS_AS( ui.send(testOID, tm, -20), uniset::Exception ); REQUIRE_THROWS_AS( ui.send(testOID, tm, -20), uniset::Exception );
REQUIRE_THROWS_AS( ui.send(testOID, tm, DefaultObjectId), uniset::Exception ); REQUIRE_THROWS_AS( ui.send(testOID, tm, DefaultObjectId), uniset::Exception );
REQUIRE_THROWS_AS( ui.getChangedTime(sid, -20), uniset::Exception ); REQUIRE_THROWS_AS( ui.getTimeChange(sid, -20), uniset::Exception );
REQUIRE_THROWS_AS( ui.getChangedTime(sid, DefaultObjectId), uniset::Exception ); REQUIRE_THROWS_AS( ui.getTimeChange(sid, DefaultObjectId), uniset::Exception );
REQUIRE_THROWS_AS( ui.getChangedTime(sid, conf->getLocalNode()), uniset::Exception ); REQUIRE_THROWS_AS( ui.getTimeChange(sid, conf->getLocalNode()), uniset::Exception );
CHECK_FALSE( ui.isExist(sid) ); CHECK_FALSE( ui.isExist(sid) );
CHECK_FALSE( ui.isExist(sid, DefaultObjectId) ); CHECK_FALSE( ui.isExist(sid, DefaultObjectId) );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment