Commit 006ecf4d authored by Ronan's avatar Ronan

feat(Conference): hide private attributes of Conference classes (feat Benjamin...

feat(Conference): hide private attributes of Conference classes (feat Benjamin Reis aka Ben Rei Jeb)
parent d1c80c1e
......@@ -40,10 +40,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "c-wrapper/c-wrapper.h"
#include "call/call-p.h"
#include "chat/chat-room/chat-room.h"
#include "conference/session/call-session.h"
#include "conference/participant.h"
#include "conference/session/call-session-p.h"
#include "conference/session/media-session.h"
#include "conference/session/call-session.h"
#include "conference/session/media-session-p.h"
#include "conference/session/media-session.h"
using namespace LinphonePrivate;
......
......@@ -117,6 +117,13 @@ class ObjectPrivate;
friend class Tester;
#endif
// Generic public helper. (Neither ClonableObject nor Object.)
// `void *` is used to avoid downcasting.
template<typename T>
constexpr T *getPublicHelper (void *object, const void *) {
return static_cast<T *>(object);
}
template<typename T, typename U>
inline T *getPublicHelper (const U *map, const ClonableObjectPrivate *context) {
auto it = map->find(context);
......
......@@ -42,6 +42,16 @@ namespace Utils {
return object.get();
}
template<typename T>
LINPHONE_PUBLIC constexpr T *getPtr (std::unique_ptr<T> &object) {
return object.get();
}
template<typename T>
LINPHONE_PUBLIC constexpr T *getPtr (const std::unique_ptr<T> &object) {
return object.get();
}
template<typename T>
LINPHONE_PUBLIC constexpr T *getPtr (T *object) {
return object;
......
......@@ -54,9 +54,11 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
chat/modifier/encryption-chat-message-modifier.h
chat/modifier/multipart-chat-message-modifier.h
conference/conference-listener.h
conference/conference-p.h
conference/conference.h
conference/local-conference-event-handler-p.h
conference/local-conference-event-handler.h
conference/local-conference-p.h
conference/local-conference.h
conference/params/call-session-params-p.h
conference/params/call-session-params.h
......@@ -67,6 +69,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
conference/participant.h
conference/remote-conference-event-handler-p.h
conference/remote-conference-event-handler.h
conference/remote-conference-p.h
conference/remote-conference.h
conference/session/call-session-listener.h
conference/session/call-session-p.h
......
......@@ -230,12 +230,12 @@ LinphoneParticipant *linphone_chat_room_find_participant (const LinphoneChatRoom
}
const LinphoneAddress *linphone_chat_room_get_conference_address (const LinphoneChatRoom *cr) {
if (cr->conferenceAddressCache) {
if (cr->conferenceAddressCache)
linphone_address_unref(cr->conferenceAddressCache);
}
auto addr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress();
if (addr)
cr->conferenceAddressCache = linphone_address_new(addr->asString().c_str());
const LinphonePrivate::Address &address = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress();
if (address.isValid())
cr->conferenceAddressCache = linphone_address_new(address.asString().c_str());
else
cr->conferenceAddressCache = nullptr;
return cr->conferenceAddressCache;
......
......@@ -20,10 +20,12 @@
#ifndef _CALL_P_H_
#define _CALL_P_H_
#include "call-listener.h"
#include "call.h"
#include "conference/conference.h"
#include "object/object-p.h"
// TODO: Remove me later.
#include "private.h"
// =============================================================================
......
......@@ -17,7 +17,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/utils/utils.h"
#include "basic-chat-room-p.h"
#include "conference/participant.h"
#include "logger/logger.h"
// =============================================================================
......@@ -57,9 +60,9 @@ shared_ptr<Participant> BasicChatRoom::findParticipant (const Address &addr) con
return nullptr;
}
const Address *BasicChatRoom::getConferenceAddress () const {
const Address &BasicChatRoom::getConferenceAddress () const {
lError() << "a BasicChatRoom does not have a conference address";
return nullptr;
return Utils::getEmptyConstRefObject<Address>();
}
int BasicChatRoom::getNbParticipants () const {
......
......@@ -40,7 +40,7 @@ public:
void addParticipants (const std::list<Address> &addresses, const CallSessionParams *params, bool hasMedia) override;
bool canHandleParticipants () const override;
std::shared_ptr<Participant> findParticipant (const Address &addr) const override;
const Address *getConferenceAddress () const override;
const Address &getConferenceAddress () const override;
int getNbParticipants () const override;
std::list<std::shared_ptr<Participant>> getParticipants () const override;
const std::string &getSubject () const override;
......
......@@ -41,7 +41,7 @@ public:
void addParticipants (const std::list<Address> &addresses, const CallSessionParams *params, bool hasMedia) override;
bool canHandleParticipants () const override;
std::shared_ptr<Participant> findParticipant (const Address &addr) const override;
const Address *getConferenceAddress () const override;
const Address &getConferenceAddress () const override;
int getNbParticipants () const override;
std::list<std::shared_ptr<Participant>> getParticipants () const override;
const std::string &getSubject () const override;
......@@ -69,7 +69,7 @@ private:
void onCallSessionStateChanged (const std::shared_ptr<const CallSession> &session, LinphoneCallState state, const std::string &message) override;
private:
L_DECLARE_PRIVATE(ClientGroupChatRoom);
L_DECLARE_PRIVATE_T(ClientGroupChatRoom, ChatRoom);
L_DISABLE_COPY(ClientGroupChatRoom);
};
......
......@@ -19,6 +19,7 @@
#include "c-wrapper/c-wrapper.h"
#include "chat/chat-message/chat-message-p.h"
#include "conference/participant.h"
#include "logger/logger.h"
#include "real-time-text-chat-room-p.h"
......@@ -150,9 +151,9 @@ shared_ptr<Participant> RealTimeTextChatRoom::findParticipant (const Address &ad
return nullptr;
}
const Address *RealTimeTextChatRoom::getConferenceAddress () const {
const Address &RealTimeTextChatRoom::getConferenceAddress () const {
lError() << "a RealTimeTextChatRoom does not have a conference address";
return nullptr;
return Utils::getEmptyConstRefObject<Address>();
}
int RealTimeTextChatRoom::getNbParticipants () const {
......
......@@ -43,7 +43,7 @@ public:
void addParticipants (const std::list<Address> &addresses, const CallSessionParams *params, bool hasMedia) override;
bool canHandleParticipants () const override;
std::shared_ptr<Participant> findParticipant (const Address &addr) const override;
const Address *getConferenceAddress () const override;
const Address &getConferenceAddress () const override;
int getNbParticipants () const override;
std::list<std::shared_ptr<Participant>> getParticipants () const override;
const std::string &getSubject () const override;
......
......@@ -23,14 +23,16 @@
#include <list>
#include <memory>
#include "address/address.h"
#include "conference/participant.h"
#include "conference/params/call-session-params.h"
#include "linphone/utils/general.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class Address;
class CallSessionParams;
class Participant;
class LINPHONE_PUBLIC ConferenceInterface {
public:
virtual ~ConferenceInterface() = default;
......@@ -39,7 +41,7 @@ public:
virtual void addParticipants (const std::list<Address> &addresses, const CallSessionParams *params, bool hasMedia) = 0;
virtual bool canHandleParticipants () const = 0;
virtual std::shared_ptr<Participant> findParticipant (const Address &addr) const = 0;
virtual const Address *getConferenceAddress () const = 0;
virtual const Address &getConferenceAddress () const = 0;
virtual int getNbParticipants () const = 0;
virtual std::list<std::shared_ptr<Participant>> getParticipants () const = 0;
virtual const std::string &getSubject () const = 0;
......
......@@ -20,12 +20,16 @@
#ifndef _CONFERENCE_LISTENER_H_
#define _CONFERENCE_LISTENER_H_
#include "address/address.h"
#include <string>
#include "linphone/utils/general.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class Address;
class ConferenceListener {
public:
virtual void onConferenceCreated (const Address &addr) = 0;
......@@ -41,4 +45,3 @@ public:
LINPHONE_END_NAMESPACE
#endif // ifndef _CONFERENCE_LISTENER_H_
/*
* conference-p.h
* Copyright (C) 2010-2017 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CONFERENCE_P_H_
#define _CONFERENCE_P_H_
#include <list>
#include <memory>
#include "linphone/types.h"
#include "address/address.h"
#include "conference.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class CallListener;
class Participant;
class ConferencePrivate {
public:
Address conferenceAddress;
std::list<std::shared_ptr<Participant>> participants;
protected:
LinphoneCore *core = nullptr;
CallListener *callListener = nullptr;
std::shared_ptr<Participant> activeParticipant;
std::shared_ptr<Participant> me;
std::string subject;
Conference *mPublic = nullptr;
private:
L_DECLARE_PUBLIC(Conference);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _CONFERENCE_P_H_
......@@ -17,27 +17,45 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "participant-p.h"
#include "conference.h"
#include "call/call-listener.h"
#include "conference-p.h"
#include "conference/session/call-session-p.h"
#include "logger/logger.h"
#include "participant-p.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// =============================================================================
Conference::Conference (ConferencePrivate &p, LinphoneCore *core, const Address &myAddress, CallListener *listener) : mPrivate(&p) {
L_D();
d->mPublic = this;
d->core = core;
d->callListener = listener;
d->me = ObjectFactory::create<Participant>(myAddress);
}
Conference::Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener)
: core(core), callListener(listener) {
me = ObjectFactory::create<Participant>(myAddress);
Conference::~Conference () {
delete mPrivate;
}
// -----------------------------------------------------------------------------
shared_ptr<Participant> Conference::getActiveParticipant () const {
return activeParticipant;
L_D();
return d->activeParticipant;
}
shared_ptr<Participant> Conference::getMe () const {
L_D();
return d->me;
}
LinphoneCore *Conference::getCore () const {
L_D();
return d->core;
}
// -----------------------------------------------------------------------------
......@@ -61,20 +79,24 @@ bool Conference::canHandleParticipants () const {
return true;
}
const Address *Conference::getConferenceAddress () const {
return &conferenceAddress;
const Address &Conference::getConferenceAddress () const {
L_D();
return d->conferenceAddress;
}
int Conference::getNbParticipants () const {
return static_cast<int>(participants.size());
L_D();
return static_cast<int>(d->participants.size());
}
list<shared_ptr<Participant>> Conference::getParticipants () const {
return participants;
L_D();
return d->participants;
}
const string &Conference::getSubject () const {
return subject;
L_D();
return d->subject;
}
void Conference::join () {}
......@@ -90,110 +112,132 @@ void Conference::removeParticipants (const list<shared_ptr<Participant>> &partic
removeParticipant(p);
}
void Conference::setParticipantAdminStatus (std::shared_ptr<Participant> &participant, bool isAdmin) {
void Conference::setParticipantAdminStatus (shared_ptr<Participant> &participant, bool isAdmin) {
lError() << "Conference class does not handle setParticipantAdminStatus() generically";
}
void Conference::setSubject (const string &subject) {
this->subject = subject;
L_D();
d->subject = subject;
}
// -----------------------------------------------------------------------------
void Conference::onAckBeingSent (const std::shared_ptr<const CallSession> &session, LinphoneHeaders *headers) {
if (callListener)
callListener->onAckBeingSent(headers);
void Conference::onAckBeingSent (const shared_ptr<const CallSession> &session, LinphoneHeaders *headers) {
L_D();
if (d->callListener)
d->callListener->onAckBeingSent(headers);
}
void Conference::onAckReceived (const std::shared_ptr<const CallSession> &session, LinphoneHeaders *headers) {
if (callListener)
callListener->onAckReceived(headers);
void Conference::onAckReceived (const shared_ptr<const CallSession> &session, LinphoneHeaders *headers) {
L_D();
if (d->callListener)
d->callListener->onAckReceived(headers);
}
void Conference::onCallSessionAccepted (const std::shared_ptr<const CallSession> &session) {
if (callListener)
callListener->onIncomingCallToBeAdded();
void Conference::onCallSessionAccepted (const shared_ptr<const CallSession> &session) {
L_D();
if (d->callListener)
d->callListener->onIncomingCallToBeAdded();
}
void Conference::onCallSessionSetReleased (const std::shared_ptr<const CallSession> &session) {
if (callListener)
callListener->onCallSetReleased();
void Conference::onCallSessionSetReleased (const shared_ptr<const CallSession> &session) {
L_D();
if (d->callListener)
d->callListener->onCallSetReleased();
}
void Conference::onCallSessionSetTerminated (const std::shared_ptr<const CallSession> &session) {
if (callListener)
callListener->onCallSetTerminated();
void Conference::onCallSessionSetTerminated (const shared_ptr<const CallSession> &session) {
L_D();
if (d->callListener)
d->callListener->onCallSetTerminated();
}
void Conference::onCallSessionStateChanged (const std::shared_ptr<const CallSession> &session, LinphoneCallState state, const string &message) {
if (callListener)
callListener->onCallStateChanged(state, message);
void Conference::onCallSessionStateChanged (const shared_ptr<const CallSession> &session, LinphoneCallState state, const string &message) {
L_D();
if (d->callListener)
d->callListener->onCallStateChanged(state, message);
}
void Conference::onCheckForAcceptation (const std::shared_ptr<const CallSession> &session) {
if (callListener)
callListener->onCheckForAcceptation();
void Conference::onCheckForAcceptation (const shared_ptr<const CallSession> &session) {
L_D();
if (d->callListener)
d->callListener->onCheckForAcceptation();
}
void Conference::onIncomingCallSessionStarted (const std::shared_ptr<const CallSession> &session) {
if (callListener)
callListener->onIncomingCallStarted();
void Conference::onIncomingCallSessionStarted (const shared_ptr<const CallSession> &session) {
L_D();
if (d->callListener)
d->callListener->onIncomingCallStarted();
}
void Conference::onEncryptionChanged (const std::shared_ptr<const CallSession> &session, bool activated, const string &authToken) {
if (callListener)
callListener->onEncryptionChanged(activated, authToken);
void Conference::onEncryptionChanged (const shared_ptr<const CallSession> &session, bool activated, const string &authToken) {
L_D();
if (d->callListener)
d->callListener->onEncryptionChanged(activated, authToken);
}
void Conference::onStatsUpdated (const LinphoneCallStats *stats) {
if (callListener)
callListener->onStatsUpdated(stats);
L_D();
if (d->callListener)
d->callListener->onStatsUpdated(stats);
}
void Conference::onResetCurrentSession (const std::shared_ptr<const CallSession> &session) {
if (callListener)
callListener->onResetCurrentCall();
void Conference::onResetCurrentSession (const shared_ptr<const CallSession> &session) {
L_D();
if (d->callListener)
d->callListener->onResetCurrentCall();
}
void Conference::onSetCurrentSession (const std::shared_ptr<const CallSession> &session) {
if (callListener)
callListener->onSetCurrentCall();
void Conference::onSetCurrentSession (const shared_ptr<const CallSession> &session) {
L_D();
if (d->callListener)
d->callListener->onSetCurrentCall();
}
void Conference::onFirstVideoFrameDecoded (const std::shared_ptr<const CallSession> &session) {
if (callListener)
callListener->onFirstVideoFrameDecoded();
void Conference::onFirstVideoFrameDecoded (const shared_ptr<const CallSession> &session) {
L_D();
if (d->callListener)
d->callListener->onFirstVideoFrameDecoded();
}
void Conference::onResetFirstVideoFrameDecoded (const std::shared_ptr<const CallSession> &session) {
if (callListener)
callListener->onResetFirstVideoFrameDecoded();
void Conference::onResetFirstVideoFrameDecoded (const shared_ptr<const CallSession> &session) {
L_D();
if (d->callListener)
d->callListener->onResetFirstVideoFrameDecoded();
}
// -----------------------------------------------------------------------------
shared_ptr<Participant> Conference::findParticipant (const Address &addr) const {
L_D();
Address testedAddr = addr;
testedAddr.setPort(0);
for (const auto &participant : participants) {
for (const auto &participant : d->participants) {
Address participantAddr = participant->getAddress();
participantAddr.setPort(0);
if (testedAddr.weakEqual(participantAddr))
return participant;
}
return nullptr;
}
shared_ptr<Participant> Conference::findParticipant (const shared_ptr<const CallSession> &session) const {
for (const auto &participant : participants) {
L_D();
for (const auto &participant : d->participants) {
if (participant->getPrivate()->getSession() == session)
return participant;
}
return nullptr;
}
bool Conference::isMe (const Address &addr) const {
Address cleanedMe = me->getAddress();
L_D();
Address cleanedMe = d->me->getAddress();
cleanedMe.setPort(0);
Address cleanedAddr = addr;
cleanedAddr.setPort(0);
......
......@@ -22,39 +22,36 @@
#include "linphone/types.h"
#include "address/address.h"
#include "call/call-listener.h"
#include "conference/conference-interface.h"
#include "conference/params/call-session-params.h"
#include "conference/participant.h"
#include "conference/session/call-session-listener.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class CallListener;
class CallSessionPrivate;
class ConferencePrivate;
class LINPHONE_PUBLIC Conference : public ConferenceInterface, public CallSessionListener {
friend class CallSessionPrivate;
public:
virtual ~Conference() = default;
virtual ~Conference();
std::shared_ptr<Participant> getActiveParticipant () const;
std::shared_ptr<Participant> getMe () const { return me; }
std::shared_ptr<Participant> getMe () const;
LinphoneCore * getCore () const { return core; }
LinphoneCore * getCore () const;
std::shared_ptr<Participant> findParticipant (const std::shared_ptr<const CallSession> &session) const;
public:
/* ConferenceInterface */
void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override;
void addParticipants (const std::list<Address> &addresses, const CallSessionParams *params, bool hasMedia) override;
bool canHandleParticipants () const override;
std::shared_ptr<Participant> findParticipant (const Address &addr) const override;
const Address *getConferenceAddress () const override;
const Address &getConferenceAddress () const override;
int getNbParticipants () const override;
std::list<std::shared_ptr<Participant>> getParticipants () const override;
const std::string &getSubject () const override;
......@@ -83,21 +80,19 @@ private:
void onResetFirstVideoFrameDecoded (const std::shared_ptr<const CallSession> &session) override;
protected:
explicit Conference (LinphoneCore *core, const Address &myAddress, CallListener *listener = nullptr);
bool isMe (const Address &addr) const ;
explicit Conference (
ConferencePrivate &p,
LinphoneCore *core,
const Address &myAddress,
CallListener *listener = nullptr
);
protected:
LinphoneCore *core = nullptr;
CallListener *callListener = nullptr;
bool isMe (const Address &addr) const;
std::shared_ptr<Participant> activeParticipant;
std::shared_ptr<Participant> me;
std::list<std::shared_ptr<Participant>> participants;
Address conferenceAddress;
std::string subject;
ConferencePrivate *mPrivate = nullptr;
private:
L_DECLARE_PRIVATE(Conference);
L_DISABLE_COPY(Conference);
};
......
......@@ -78,7 +78,7 @@ string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo
}
string LocalConferenceEventHandlerPrivate::createNotifyFullState () {
string entity = conf->getConferenceAddress()->asStringUriOnly();
string entity = conf->getConferenceAddress().asStringUriOnly();
string subject = conf->getSubject();
ConferenceType confInfo = ConferenceType(entity);
UsersType users;
......@@ -112,7 +112,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState () {
}
string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr) {
string entity = conf->getConferenceAddress()->asStringUriOnly();
string entity = conf->getConferenceAddress().asStringUriOnly();
ConferenceType confInfo = ConferenceType(entity);
UsersType users;
confInfo.setUsers(users);
......@@ -142,7 +142,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const A
}
string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const Address &addr) {
string entity = conf->getConferenceAddress()->asStringUriOnly();
string entity = conf->getConferenceAddress().asStringUriOnly();
ConferenceType confInfo = ConferenceType(entity);
UsersType users;
confInfo.setUsers(users);
......@@ -156,7 +156,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantRemoved (const
}
string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const Address &addr, bool isAdmin) {
string entity = conf->getConferenceAddress()->asStringUriOnly();
string entity = conf->getConferenceAddress().asStringUriOnly();
ConferenceType confInfo = ConferenceType(entity);
UsersType users;
confInfo.setUsers(users);
......@@ -173,7 +173,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const
}
string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () {
string entity = conf->getConferenceAddress()->asStringUriOnly();
string entity = conf->getConferenceAddress().asStringUriOnly();
string subject = conf->getSubject();
ConferenceType confInfo = ConferenceType(entity);
ConferenceDescriptionType confDescr = ConferenceDescriptionType();
......@@ -184,7 +184,7 @@ string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged () {
}
string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (const Address &addr, const Address &gruu) {
string entity = conf->getConferenceAddress()->asStringUriOnly();
string entity = conf->getConferenceAddress().asStringUriOnly();
string subject = conf->getSubject();
ConferenceType confInfo = ConferenceType(entity);
UsersType users;
......@@ -209,7 +209,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceAdded (c
}
string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved (const Address &addr, const Address &gruu) {
string entity = conf->getConferenceAddress()->asStringUriOnly();
string entity = conf->getConferenceAddress().asStringUriOnly();
string subject = conf->getSubject();
ConferenceType confInfo = ConferenceType(entity);
UsersType users;
......@@ -237,7 +237,7 @@ void LocalConferenceEventHandlerPrivate::sendNotify (const string &notify, const
LinphoneAddress *cAddr = linphone_address_new(addr.asString().c_str());
LinphoneEvent *lev = linphone_core_create_notify(core, cAddr, "conference");
// Fix the From header to put the chat room URI
lev->op->set_from(conf->getConferenceAddress()->asString().c_str());
lev->op->set_from(conf->getConferenceAddress().asString().c_str());
linphone_address_unref(cAddr);
doNotify(notify, lev);
}
......
/*
* local-conference-p.h
* Copyright (C) 2010-2017 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the