<commit_before>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
	Copyright (C) 2010-2015  Belledonne Communications SARL, All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
#include <dirent.h>

#include "pushnotificationservice.hh"
#include "pushnotificationclient.hh"
#include "pushnotificationclient_wp.hh"
#include "common.hh"

#include <sstream>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/err.h>
#include <openssl/pem.h>

using namespace std;

static const char *APN_DEV_ADDRESS = "gateway.sandbox.push.apple.com";
static const char *APN_PROD_ADDRESS = "gateway.push.apple.com";
static const char *APN_PORT = "2195";

static const char *GPN_ADDRESS = "gcm-http.googleapis.com";
static const char *GPN_PORT = "443";

static const char *FIREBASE_ADDRESS = "fcm.googleapis.com";
static const char *FIREBASE_PORT = "443";

static const char *WPPN_PORT = "443";

PushNotificationService::PushNotificationService(int maxQueueSize)
: mMaxQueueSize(maxQueueSize), mClients(), mCountFailed(NULL), mCountSent(NULL) {
	SSL_library_init();
	SSL_load_error_strings();
}

PushNotificationService::~PushNotificationService() {
	ERR_free_strings();
}

int PushNotificationService::sendPush(const std::shared_ptr<PushNotificationRequest> &pn){
	std::shared_ptr<PushNotificationClient> client = mClients[pn->getAppIdentifier()];
	bool isW10 = (pn->getType().compare(string("w10")) == 0);
	bool isWP = (pn->getType().compare(string("wp")) == 0);
	if (client == 0 && (isW10 || isWP)) {
		// In Windows case we can't create all push notification clients at start up since we need to wait the registration of all AppID
		// Therefore we create the push notification client just before sending the push.
		if (isW10 && (mWindowsPhonePackageSID.empty() || mWindowsPhoneApplicationSecret.empty())) {
			SLOGE << "Windows Phone not configured for push notifications ("
				"package sid is " << (mWindowsPhonePackageSID.empty() ? "NOT configured" : "configured") << " and " <<
				"application secret is " << (mWindowsPhoneApplicationSecret.empty() ? "NOT configured" : "configured") << ").";
			return -1;
		} else {
			string wpClient = pn->getAppIdentifier();

			SSL_CTX* ctx = SSL_CTX_new(TLSv1_2_method());
			SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

			LOGD("Creating PN client for %s", pn->getAppIdentifier().c_str());
			if(isW10) {
				mClients[wpClient] = std::make_shared<PushNotificationClientWp>(wpClient, this, ctx,
												pn->getAppIdentifier(), WPPN_PORT, mMaxQueueSize, true, mWindowsPhonePackageSID, mWindowsPhoneApplicationSecret);
			} else {
				mClients[wpClient] = std::make_shared<PushNotificationClient>(wpClient, this, ctx,
												pn->getAppIdentifier(), "80", mMaxQueueSize, false);
			}
			client = mClients[wpClient];
		}
	} else {
		SLOGE << "No push notification client available for push notification request : " << pn;
		return -1;
	}
	client->sendPush(pn);
	return 0;
}

bool PushNotificationService::isIdle() {
	map<string, std::shared_ptr<PushNotificationClient>>::const_iterator it;
	for (it = mClients.begin(); it != mClients.end(); ++it) {
		if (!it->second->isIdle()) {
			return false;
		}
	}
	return true;
}

void PushNotificationService::setupGenericClient(const url_t *url) {
	SSL_CTX* ctx = SSL_CTX_new(TLSv1_client_method());
	SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

	mClients["generic"] = std::make_shared<PushNotificationClient>("generic", this, ctx, url->url_host, url_port(url),
		mMaxQueueSize, false);
}

/* Utility function to convert ASN1_TIME to a printable string in a buffer */
static int ASN1_TIME_toString( const ASN1_TIME* time, char* buffer, uint32_t buff_length){
	int write = 0;
	BIO* bio = BIO_new(BIO_s_mem());
	if (bio) {
		if (ASN1_TIME_print(bio, time))
			write = BIO_read(bio, buffer, buff_length-1);
		BIO_free_all(bio);
	}
	buffer[write]='\0';
	return write;
}

bool PushNotificationService::isCertExpired( const std::string &certPath ){
	bool expired = true;
	BIO* certbio = BIO_new(BIO_s_file());
	int err = BIO_read_filename(certbio, certPath.c_str());
	if( err == 0 ){
		LOGE("BIO_read_filename failed for %s", certPath.c_str());
		BIO_free_all(certbio);
		return expired;
	}

	X509* cert = PEM_read_bio_X509(certbio, NULL, 0, 0);
	if( !cert ){
		char buf[128] = {};
		unsigned long error = ERR_get_error();
		ERR_error_string(error, buf);
		LOGE("Couldn't parse certificate at %s : %s", certPath.c_str(), buf);
		BIO_free_all(certbio);
		return expired;
	} else {
		ASN1_TIME *notBefore = X509_get_notBefore(cert);
		ASN1_TIME *notAfter = X509_get_notAfter(cert);
		char beforeStr[128] = {};
		char afterStr[128] = {};
		int validDates = ( ASN1_TIME_toString(notBefore, beforeStr, 128) && ASN1_TIME_toString(notAfter, afterStr, 128));
		if( X509_cmp_current_time(notBefore) <= 0 && X509_cmp_current_time(notAfter) >= 0 ) {
			LOGD("Certificate %s has a valid expiration: %s.", certPath.c_str(), afterStr);
			expired = false;
		} else {
			// the certificate has an expire or not before value that makes it not valid regarding the server's date.
			if (validDates) {
				LOGD("Certificate %s is expired or not yet valid! Not Before: %s, Not After: %s", certPath.c_str(),
					beforeStr, afterStr);
			} else {
				LOGD("Certificate %s is expired or not yet valid!", certPath.c_str());
			}
		}
	}
	X509_free(cert);
	BIO_free_all(certbio);

	return expired;
}

int handle_verify_callback(X509_STORE_CTX* mCtx, void* ud) {
	char subject_name[256];

	X509 *cert = X509_STORE_CTX_get_current_cert(mCtx);
	if (!cert) {
		SLOGE << "No certificate found!";
		return 0;
	}
	X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
	SLOGD << "Verifying " << subject_name;

	int error = X509_STORE_CTX_get_error(mCtx);
	if( error != 0 ){
		switch (error) {
			case X509_V_ERR_CERT_NOT_YET_VALID:
			case X509_V_ERR_CRL_NOT_YET_VALID:
			SLOGE << "Certificate for " <<  subject_name << " is not yet valid. Push won't work.";
			break;
			case X509_V_ERR_CERT_HAS_EXPIRED:
			case X509_V_ERR_CRL_HAS_EXPIRED:
			SLOGE << "Certificate for " <<  subject_name << " is expired. Push won't work.";
			break;
			default:{
				const char* errString = X509_verify_cert_error_string(error);
				SLOGE << "Certificate for " << subject_name << " is invalid (reason: " << error << ": " << (errString ? errString:"unknown") << "). Push won't work.";
				break;
			}
		}
	}

	return 0;
}

void PushNotificationService::setupiOSClient(const std::string &certdir, const std::string &cafile) {
	struct dirent *dirent;
	DIR *dirp;

	dirp = opendir(certdir.c_str());
	if (dirp == NULL) {
		LOGE("Could not open push notification certificates directory (%s): %s", certdir.c_str(), strerror(errno));
		return;
	}
	SLOGD << "Searching push notification client on dir [" << certdir << "]";

	while (true) {
		errno = 0;
		if ((dirent = readdir(dirp)) == NULL) {
			if (errno)
				SLOGE << "Cannot read dir [" << certdir << "] because [" << strerror(errno) << "]";
			break;
		}

		string cert = string(dirent->d_name);
		// only consider files which end with .pem
		string suffix = ".pem";
		if (cert.compare(".") == 0 || cert.compare("..") == 0 || cert.length() <= suffix.length() ||
			(cert.compare(cert.length() - suffix.length(), suffix.length(), suffix) != 0)) {
			continue;
		}
		/*March 2016: Yes Apple production push server doesn't support TLS > 1.0*/
		SSL_CTX* ctx = SSL_CTX_new(TLSv1_client_method());
		if (!ctx) {
			SLOGE << "Could not create ctx!";
			ERR_print_errors_fp(stderr);
			continue;
		}

		if (cafile.empty()) {
			SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
		} else {
			SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
			SSL_CTX_set_cert_verify_callback(ctx, handle_verify_callback, NULL);
		}

		if(! SSL_CTX_load_verify_locations(ctx, cafile.empty()?NULL:cafile.c_str(), "/etc/ssl/certs")) {
			SLOGE << "Error loading trust store";
			ERR_print_errors_fp(stderr);
			SSL_CTX_free(ctx);
			continue;
		}

		string certpath = string(certdir) + "/" + cert;
		if (!cert.empty()) {
			int error = SSL_CTX_use_certificate_file(ctx, certpath.c_str(), SSL_FILETYPE_PEM);
			if (error != 1) {
				LOGE("SSL_CTX_use_certificate_file for %s failed: %d", certpath.c_str(), error);
				continue;
			} else if ( isCertExpired(certpath) ){
				LOGEN("Certificate %s is expired! You won't be able to use it for push notifications. Please update your certificate or remove it entirely.", certpath.c_str());
			}
		}
		if (!certpath.empty()) {
			int error = SSL_CTX_use_PrivateKey_file(ctx, certpath.c_str(), SSL_FILETYPE_PEM);
			if (error != 1 || SSL_CTX_check_private_key(ctx) != 1) {
				SLOGE << "Private key does not match the certificate public key for " << certpath << ": " << error;
				continue;
			}
		}

		string certName = cert.substr(0, cert.size() - 4); // Remove .pem at the end of cert
		const char *apn_server = (certName.find(".dev") != string::npos) ? APN_DEV_ADDRESS : APN_PROD_ADDRESS;
		mClients[certName] = std::make_shared<PushNotificationClient>(cert, this, ctx, apn_server, APN_PORT, mMaxQueueSize, true);
		SLOGD << "Adding ios push notification client [" << certName << "]";
	}
	closedir(dirp);
}

void PushNotificationService::setupAndroidClient(const std::map<std::string, std::string> googleKeys) {
	map<string, string>::const_iterator it;
	for (it = googleKeys.begin(); it != googleKeys.end(); ++it) {
		string android_app_id = it->first;

		SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
		SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

		mClients[android_app_id] = std::make_shared<PushNotificationClient>("google", this, ctx, GPN_ADDRESS, GPN_PORT, mMaxQueueSize, true);
		SLOGD << "Adding android push notification client [" << android_app_id << "]";
	}
}

void PushNotificationService::setupFirebaseClient(const std::map<std::string, std::string> firebaseKeys) {
	map<string, string>::const_iterator it;
	for (it = firebaseKeys.begin(); it != firebaseKeys.end(); ++it) {
		string firebase_app_id = it->first;

		SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
		SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

		mClients[firebase_app_id] = std::make_shared<PushNotificationClient>("firebase", this, ctx, FIREBASE_ADDRESS, FIREBASE_PORT, mMaxQueueSize, true);
		SLOGD << "Adding firebase push notification client [" << firebase_app_id << "]";
	}
}

void PushNotificationService::setupWindowsPhoneClient(const std::string& packageSID, const std::string& applicationSecret) {
	mWindowsPhonePackageSID = packageSID;
	mWindowsPhoneApplicationSecret = applicationSecret;
	SLOGD << "Adding Windows push notification client for pacakge SID [" << packageSID << "]";
}
<commit_msg>Fix push issue<commit_after>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
	Copyright (C) 2010-2015  Belledonne Communications SARL, All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
#include <dirent.h>

#include "pushnotificationservice.hh"
#include "pushnotificationclient.hh"
#include "pushnotificationclient_wp.hh"
#include "common.hh"

#include <sstream>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/err.h>
#include <openssl/pem.h>

using namespace std;

static const char *APN_DEV_ADDRESS = "gateway.sandbox.push.apple.com";
static const char *APN_PROD_ADDRESS = "gateway.push.apple.com";
static const char *APN_PORT = "2195";

static const char *GPN_ADDRESS = "gcm-http.googleapis.com";
static const char *GPN_PORT = "443";

static const char *FIREBASE_ADDRESS = "fcm.googleapis.com";
static const char *FIREBASE_PORT = "443";

static const char *WPPN_PORT = "443";

PushNotificationService::PushNotificationService(int maxQueueSize)
: mMaxQueueSize(maxQueueSize), mClients(), mCountFailed(NULL), mCountSent(NULL) {
	SSL_library_init();
	SSL_load_error_strings();
}

PushNotificationService::~PushNotificationService() {
	ERR_free_strings();
}

int PushNotificationService::sendPush(const std::shared_ptr<PushNotificationRequest> &pn){
	std::shared_ptr<PushNotificationClient> client = mClients[pn->getAppIdentifier()];
	if (client == 0) {
		bool isW10 = (pn->getType().compare(string("w10")) == 0);
		bool isWP = (pn->getType().compare(string("wp")) == 0);
		if(isW10 || isWP) {
			// In Windows case we can't create all push notification clients at start up since we need to wait the registration of all AppID
			// Therefore we create the push notification client just before sending the push.
			if (isW10 && (mWindowsPhonePackageSID.empty() || mWindowsPhoneApplicationSecret.empty())) {
				SLOGE << "Windows Phone not configured for push notifications ("
					"package sid is " << (mWindowsPhonePackageSID.empty() ? "NOT configured" : "configured") << " and " <<
					"application secret is " << (mWindowsPhoneApplicationSecret.empty() ? "NOT configured" : "configured") << ").";
				return -1;
			} else {
				string wpClient = pn->getAppIdentifier();

				SSL_CTX* ctx = SSL_CTX_new(TLSv1_2_method());
				SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

				LOGD("Creating PN client for %s", pn->getAppIdentifier().c_str());
				if(isW10) {
					mClients[wpClient] = std::make_shared<PushNotificationClientWp>(wpClient, this, ctx,
																					pn->getAppIdentifier(), WPPN_PORT, mMaxQueueSize, true, mWindowsPhonePackageSID, mWindowsPhoneApplicationSecret);
				} else {
					mClients[wpClient] = std::make_shared<PushNotificationClient>(wpClient, this, ctx,
												pn->getAppIdentifier(), "80", mMaxQueueSize, false);
				}
				client = mClients[wpClient];
			}
		} else {
			SLOGE << "No push notification client available for push notification request : " << pn;
			return -1;
		}
	}
	client->sendPush(pn);
	return 0;
}

bool PushNotificationService::isIdle() {
	map<string, std::shared_ptr<PushNotificationClient>>::const_iterator it;
	for (it = mClients.begin(); it != mClients.end(); ++it) {
		if (!it->second->isIdle()) {
			return false;
		}
	}
	return true;
}

void PushNotificationService::setupGenericClient(const url_t *url) {
	SSL_CTX* ctx = SSL_CTX_new(TLSv1_client_method());
	SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

	mClients["generic"] = std::make_shared<PushNotificationClient>("generic", this, ctx, url->url_host, url_port(url),
		mMaxQueueSize, false);
}

/* Utility function to convert ASN1_TIME to a printable string in a buffer */
static int ASN1_TIME_toString( const ASN1_TIME* time, char* buffer, uint32_t buff_length){
	int write = 0;
	BIO* bio = BIO_new(BIO_s_mem());
	if (bio) {
		if (ASN1_TIME_print(bio, time))
			write = BIO_read(bio, buffer, buff_length-1);
		BIO_free_all(bio);
	}
	buffer[write]='\0';
	return write;
}

bool PushNotificationService::isCertExpired( const std::string &certPath ){
	bool expired = true;
	BIO* certbio = BIO_new(BIO_s_file());
	int err = BIO_read_filename(certbio, certPath.c_str());
	if( err == 0 ){
		LOGE("BIO_read_filename failed for %s", certPath.c_str());
		BIO_free_all(certbio);
		return expired;
	}

	X509* cert = PEM_read_bio_X509(certbio, NULL, 0, 0);
	if( !cert ){
		char buf[128] = {};
		unsigned long error = ERR_get_error();
		ERR_error_string(error, buf);
		LOGE("Couldn't parse certificate at %s : %s", certPath.c_str(), buf);
		BIO_free_all(certbio);
		return expired;
	} else {
		ASN1_TIME *notBefore = X509_get_notBefore(cert);
		ASN1_TIME *notAfter = X509_get_notAfter(cert);
		char beforeStr[128] = {};
		char afterStr[128] = {};
		int validDates = ( ASN1_TIME_toString(notBefore, beforeStr, 128) && ASN1_TIME_toString(notAfter, afterStr, 128));
		if( X509_cmp_current_time(notBefore) <= 0 && X509_cmp_current_time(notAfter) >= 0 ) {
			LOGD("Certificate %s has a valid expiration: %s.", certPath.c_str(), afterStr);
			expired = false;
		} else {
			// the certificate has an expire or not before value that makes it not valid regarding the server's date.
			if (validDates) {
				LOGD("Certificate %s is expired or not yet valid! Not Before: %s, Not After: %s", certPath.c_str(),
					beforeStr, afterStr);
			} else {
				LOGD("Certificate %s is expired or not yet valid!", certPath.c_str());
			}
		}
	}
	X509_free(cert);
	BIO_free_all(certbio);

	return expired;
}

int handle_verify_callback(X509_STORE_CTX* mCtx, void* ud) {
	char subject_name[256];

	X509 *cert = X509_STORE_CTX_get_current_cert(mCtx);
	if (!cert) {
		SLOGE << "No certificate found!";
		return 0;
	}
	X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
	SLOGD << "Verifying " << subject_name;

	int error = X509_STORE_CTX_get_error(mCtx);
	if( error != 0 ){
		switch (error) {
			case X509_V_ERR_CERT_NOT_YET_VALID:
			case X509_V_ERR_CRL_NOT_YET_VALID:
			SLOGE << "Certificate for " <<  subject_name << " is not yet valid. Push won't work.";
			break;
			case X509_V_ERR_CERT_HAS_EXPIRED:
			case X509_V_ERR_CRL_HAS_EXPIRED:
			SLOGE << "Certificate for " <<  subject_name << " is expired. Push won't work.";
			break;
			default:{
				const char* errString = X509_verify_cert_error_string(error);
				SLOGE << "Certificate for " << subject_name << " is invalid (reason: " << error << ": " << (errString ? errString:"unknown") << "). Push won't work.";
				break;
			}
		}
	}

	return 0;
}

void PushNotificationService::setupiOSClient(const std::string &certdir, const std::string &cafile) {
	struct dirent *dirent;
	DIR *dirp;

	dirp = opendir(certdir.c_str());
	if (dirp == NULL) {
		LOGE("Could not open push notification certificates directory (%s): %s", certdir.c_str(), strerror(errno));
		return;
	}
	SLOGD << "Searching push notification client on dir [" << certdir << "]";

	while (true) {
		errno = 0;
		if ((dirent = readdir(dirp)) == NULL) {
			if (errno)
				SLOGE << "Cannot read dir [" << certdir << "] because [" << strerror(errno) << "]";
			break;
		}

		string cert = string(dirent->d_name);
		// only consider files which end with .pem
		string suffix = ".pem";
		if (cert.compare(".") == 0 || cert.compare("..") == 0 || cert.length() <= suffix.length() ||
			(cert.compare(cert.length() - suffix.length(), suffix.length(), suffix) != 0)) {
			continue;
		}
		/*March 2016: Yes Apple production push server doesn't support TLS > 1.0*/
		SSL_CTX* ctx = SSL_CTX_new(TLSv1_client_method());
		if (!ctx) {
			SLOGE << "Could not create ctx!";
			ERR_print_errors_fp(stderr);
			continue;
		}

		if (cafile.empty()) {
			SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
		} else {
			SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
			SSL_CTX_set_cert_verify_callback(ctx, handle_verify_callback, NULL);
		}

		if(! SSL_CTX_load_verify_locations(ctx, cafile.empty()?NULL:cafile.c_str(), "/etc/ssl/certs")) {
			SLOGE << "Error loading trust store";
			ERR_print_errors_fp(stderr);
			SSL_CTX_free(ctx);
			continue;
		}

		string certpath = string(certdir) + "/" + cert;
		if (!cert.empty()) {
			int error = SSL_CTX_use_certificate_file(ctx, certpath.c_str(), SSL_FILETYPE_PEM);
			if (error != 1) {
				LOGE("SSL_CTX_use_certificate_file for %s failed: %d", certpath.c_str(), error);
				continue;
			} else if ( isCertExpired(certpath) ){
				LOGEN("Certificate %s is expired! You won't be able to use it for push notifications. Please update your certificate or remove it entirely.", certpath.c_str());
			}
		}
		if (!certpath.empty()) {
			int error = SSL_CTX_use_PrivateKey_file(ctx, certpath.c_str(), SSL_FILETYPE_PEM);
			if (error != 1 || SSL_CTX_check_private_key(ctx) != 1) {
				SLOGE << "Private key does not match the certificate public key for " << certpath << ": " << error;
				continue;
			}
		}

		string certName = cert.substr(0, cert.size() - 4); // Remove .pem at the end of cert
		const char *apn_server = (certName.find(".dev") != string::npos) ? APN_DEV_ADDRESS : APN_PROD_ADDRESS;
		mClients[certName] = std::make_shared<PushNotificationClient>(cert, this, ctx, apn_server, APN_PORT, mMaxQueueSize, true);
		SLOGD << "Adding ios push notification client [" << certName << "]";
	}
	closedir(dirp);
}

void PushNotificationService::setupAndroidClient(const std::map<std::string, std::string> googleKeys) {
	map<string, string>::const_iterator it;
	for (it = googleKeys.begin(); it != googleKeys.end(); ++it) {
		string android_app_id = it->first;

		SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
		SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

		mClients[android_app_id] = std::make_shared<PushNotificationClient>("google", this, ctx, GPN_ADDRESS, GPN_PORT, mMaxQueueSize, true);
		SLOGD << "Adding android push notification client [" << android_app_id << "]";
	}
}

void PushNotificationService::setupFirebaseClient(const std::map<std::string, std::string> firebaseKeys) {
	map<string, string>::const_iterator it;
	for (it = firebaseKeys.begin(); it != firebaseKeys.end(); ++it) {
		string firebase_app_id = it->first;

		SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
		SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

		mClients[firebase_app_id] = std::make_shared<PushNotificationClient>("firebase", this, ctx, FIREBASE_ADDRESS, FIREBASE_PORT, mMaxQueueSize, true);
		SLOGD << "Adding firebase push notification client [" << firebase_app_id << "]";
	}
}

void PushNotificationService::setupWindowsPhoneClient(const std::string& packageSID, const std::string& applicationSecret) {
	mWindowsPhonePackageSID = packageSID;
	mWindowsPhoneApplicationSecret = applicationSecret;
	SLOGD << "Adding Windows push notification client for pacakge SID [" << packageSID << "]";
}
<|endoftext|>


<commit_before>#include "xchainer/python/array_index.h"

#include "xchainer/array_index.h"

#include "xchainer/python/slice.h"

namespace py = pybind11;

namespace xchainer {
namespace python {
namespace {

ArrayIndex MakeArrayIndex(py::handle handle) {
    if (handle.is_none()) {
        return ArrayIndex{NewAxis{}};
    }
    if (py::int_::check_(handle)) {
        return ArrayIndex{py::cast<int64_t>(handle)};
    }
    if (py::slice::check_(handle)) {
        return ArrayIndex{internal::MakeSlice(py::cast<py::slice>(handle))};
    }
    throw py::index_error("only integers, slices (`:`), and xchainer.newaxis (`None`) are valid indices");
}

std::vector<ArrayIndex> MakeArrayIndicesFromTuple(py::tuple tup) {
    std::vector<ArrayIndex> indicies;
    for (auto& handle : tup) {
        indicies.emplace_back(MakeArrayIndex(handle));
    }
    return indicies;
}

}  // namespace

namespace internal {

std::vector<ArrayIndex> MakeArrayIndices(py::handle handle) {
    if (py::tuple::check_(handle)) {
        return MakeArrayIndicesFromTuple(py::cast<py::tuple>(handle));
    }
    return {MakeArrayIndex(handle)};
}

}  // namespace internal
}  // namespace python

void InitXchainerArrayIndex(py::module& m) {
    m.attr("newaxis") = py::none();
}

}  // namespace xchainer
<commit_msg>clang-format<commit_after>#include "xchainer/python/array_index.h"

#include "xchainer/array_index.h"

#include "xchainer/python/slice.h"

namespace py = pybind11;

namespace xchainer {
namespace python {
namespace {

ArrayIndex MakeArrayIndex(py::handle handle) {
    if (handle.is_none()) {
        return ArrayIndex{NewAxis{}};
    }
    if (py::int_::check_(handle)) {
        return ArrayIndex{py::cast<int64_t>(handle)};
    }
    if (py::slice::check_(handle)) {
        return ArrayIndex{internal::MakeSlice(py::cast<py::slice>(handle))};
    }
    throw py::index_error("only integers, slices (`:`), and xchainer.newaxis (`None`) are valid indices");
}

std::vector<ArrayIndex> MakeArrayIndicesFromTuple(py::tuple tup) {
    std::vector<ArrayIndex> indicies;
    for (auto& handle : tup) {
        indicies.emplace_back(MakeArrayIndex(handle));
    }
    return indicies;
}

}  // namespace

namespace internal {

std::vector<ArrayIndex> MakeArrayIndices(py::handle handle) {
    if (py::tuple::check_(handle)) {
        return MakeArrayIndicesFromTuple(py::cast<py::tuple>(handle));
    }
    return {MakeArrayIndex(handle)};
}

}  // namespace internal
}  // namespace python

void InitXchainerArrayIndex(py::module& m) { m.attr("newaxis") = py::none(); }

}  // namespace xchainer
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "toolsettings.h"
#include "dialogs/externaltoolconfig.h"
#include "externaltool.h"
#include "externaltoolmanager.h"
#include "coreconstants.h"
#include "icore.h"

#include <utils/qtcassert.h>

#include <QCoreApplication>
#include <QFileInfo>
#include <QDir>

#include <QDebug>

using namespace Core;
using namespace Core::Internal;

ToolSettings::ToolSettings(QObject *parent) :
    IOptionsPage(parent)
{
    setId(Core::Constants::SETTINGS_ID_TOOLS);
    setDisplayName(tr("External Tools"));
    setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
    setDisplayCategory(QCoreApplication::translate("Core", Constants::SETTINGS_TR_CATEGORY_CORE));
    setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
}

QWidget *ToolSettings::widget()
{
    if (!m_widget) {
        m_widget = new ExternalToolConfig;
        m_widget->setTools(ExternalToolManager::toolsByCategory());
    }
    return m_widget;
}

static QString getUserFilePath(const QString &proposalFileName)
{
    QDir resourceDir(ICore::userResourcePath());
    if (!resourceDir.exists(QLatin1String("externaltools")))
        resourceDir.mkpath(QLatin1String("externaltools"));
    QFileInfo fi(proposalFileName);
    const QString &suffix = QLatin1String(".") + fi.completeSuffix();
    const QString &newFilePath = ICore::userResourcePath()
            + QLatin1String("/externaltools/") + fi.baseName();
    int count = 0;
    QString tryPath = newFilePath + suffix;
    while (QFile::exists(tryPath)) {
        if (count > 15)
            return QString();
        // add random number
        int number = qrand() % 1000;
        tryPath = newFilePath + QString::number(number) + suffix;
    }
    return tryPath;
}

static QString idFromDisplayName(const QString &displayName)
{
    QString id = displayName;
    QChar *c = id.data();
    while (!c->isNull()) {
        if (!c->isLetterOrNumber())
            *c = QLatin1Char('_');
        ++c;
    }
    return id;
}

static QString findUnusedId(const QString &proposal, const QMap<QString, QList<ExternalTool *> > &tools)
{
    int number = 0;
    QString result;
    bool found = false;
    do {
        result = proposal + (number > 0 ? QString::number(number) : QString::fromLatin1(""));
        ++number;
        found = false;
        QMapIterator<QString, QList<ExternalTool *> > it(tools);
        while (!found && it.hasNext()) {
            it.next();
            foreach (ExternalTool *tool, it.value()) {
                if (tool->id() == result) {
                    found = true;
                    break;
                }
            }
        }
    } while (found);
    return result;
}

void ToolSettings::apply()
{
    if (!m_widget)
        return;
    m_widget->apply();
    QMap<QString, ExternalTool *> originalTools = ExternalToolManager::toolsById();
    QMap<QString, QList<ExternalTool *> > newToolsMap = m_widget->tools();
    QMap<QString, QList<ExternalTool *> > resultMap;
    QMapIterator<QString, QList<ExternalTool *> > it(newToolsMap);
    while (it.hasNext()) {
        it.next();
        QList<ExternalTool *> items;
        foreach (ExternalTool *tool, it.value()) {
            ExternalTool *toolToAdd = 0;
            if (ExternalTool *originalTool = originalTools.take(tool->id())) {
                // check if it has different category and is custom tool
                if (tool->displayCategory() != it.key() && !tool->preset())
                    tool->setDisplayCategory(it.key());
                // check if the tool has changed
                if ((*originalTool) == (*tool)) {
                    toolToAdd = originalTool;
                } else {
                    // case 1: tool is changed preset
                    if (tool->preset() && (*tool) != (*(tool->preset()))) {
                        // check if we need to choose a new file name
                        if (tool->preset()->fileName() == tool->fileName()) {
                            const QString &fileName = QFileInfo(tool->preset()->fileName()).fileName();
                            const QString &newFilePath = getUserFilePath(fileName);
                            // TODO error handling if newFilePath.isEmpty() (i.e. failed to find a unused name)
                            tool->setFileName(newFilePath);
                        }
                        // TODO error handling
                        tool->save();
                    // case 2: tool is previously changed preset but now same as preset
                    } else if (tool->preset() && (*tool) == (*(tool->preset()))) {
                        // check if we need to delete the changed description
                        if (originalTool->fileName() != tool->preset()->fileName()
                                && QFile::exists(originalTool->fileName())) {
                            // TODO error handling
                            QFile::remove(originalTool->fileName());
                        }
                        tool->setFileName(tool->preset()->fileName());
                        // no need to save, it's the same as the preset
                    // case 3: tool is custom tool
                    } else {
                        // TODO error handling
                        tool->save();
                    }

                     // 'tool' is deleted by config page, 'originalTool' is deleted by setToolsByCategory
                    toolToAdd = new ExternalTool(tool);
                }
            } else {
                // new tool. 'tool' is deleted by config page
                QString id = idFromDisplayName(tool->displayName());
                id = findUnusedId(id, newToolsMap);
                tool->setId(id);
                // TODO error handling if newFilePath.isEmpty() (i.e. failed to find a unused name)
                tool->setFileName(getUserFilePath(id + QLatin1String(".xml")));
                // TODO error handling
                tool->save();
                toolToAdd = new ExternalTool(tool);
            }
            items.append(toolToAdd);
        }
        if (!items.isEmpty())
            resultMap.insert(it.key(), items);
    }
    // Remove tools that have been deleted from the settings (and are no preset)
    foreach (ExternalTool *tool, originalTools) {
        QTC_ASSERT(!tool->preset(), continue);
        // TODO error handling
        QFile::remove(tool->fileName());
    }

    ExternalToolManager::setToolsByCategory(resultMap);
}

void ToolSettings::finish()
{
    delete m_widget;
}
<commit_msg>Core: Fix exit strategy<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "toolsettings.h"
#include "dialogs/externaltoolconfig.h"
#include "externaltool.h"
#include "externaltoolmanager.h"
#include "coreconstants.h"
#include "icore.h"

#include <utils/qtcassert.h>

#include <QCoreApplication>
#include <QFileInfo>
#include <QDir>

#include <QDebug>

using namespace Core;
using namespace Core::Internal;

ToolSettings::ToolSettings(QObject *parent) :
    IOptionsPage(parent)
{
    setId(Core::Constants::SETTINGS_ID_TOOLS);
    setDisplayName(tr("External Tools"));
    setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
    setDisplayCategory(QCoreApplication::translate("Core", Constants::SETTINGS_TR_CATEGORY_CORE));
    setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
}

QWidget *ToolSettings::widget()
{
    if (!m_widget) {
        m_widget = new ExternalToolConfig;
        m_widget->setTools(ExternalToolManager::toolsByCategory());
    }
    return m_widget;
}

static QString getUserFilePath(const QString &proposalFileName)
{
    const QDir resourceDir(ICore::userResourcePath());
    if (!resourceDir.exists(QLatin1String("externaltools")))
        resourceDir.mkpath(QLatin1String("externaltools"));
    const QFileInfo fi(proposalFileName);
    const QString &suffix = QLatin1String(".") + fi.completeSuffix();
    const QString &newFilePath = ICore::userResourcePath()
            + QLatin1String("/externaltools/") + fi.baseName();
    int count = 0;
    QString tryPath = newFilePath + suffix;
    while (QFile::exists(tryPath)) {
        if (++count > 15)
            return QString();
        // add random number
        const int number = qrand() % 1000;
        tryPath = newFilePath + QString::number(number) + suffix;
    }
    return tryPath;
}

static QString idFromDisplayName(const QString &displayName)
{
    QString id = displayName;
    QChar *c = id.data();
    while (!c->isNull()) {
        if (!c->isLetterOrNumber())
            *c = QLatin1Char('_');
        ++c;
    }
    return id;
}

static QString findUnusedId(const QString &proposal, const QMap<QString, QList<ExternalTool *> > &tools)
{
    int number = 0;
    QString result;
    bool found = false;
    do {
        result = proposal + (number > 0 ? QString::number(number) : QString::fromLatin1(""));
        ++number;
        found = false;
        QMapIterator<QString, QList<ExternalTool *> > it(tools);
        while (!found && it.hasNext()) {
            it.next();
            foreach (ExternalTool *tool, it.value()) {
                if (tool->id() == result) {
                    found = true;
                    break;
                }
            }
        }
    } while (found);
    return result;
}

void ToolSettings::apply()
{
    if (!m_widget)
        return;
    m_widget->apply();
    QMap<QString, ExternalTool *> originalTools = ExternalToolManager::toolsById();
    QMap<QString, QList<ExternalTool *> > newToolsMap = m_widget->tools();
    QMap<QString, QList<ExternalTool *> > resultMap;
    QMapIterator<QString, QList<ExternalTool *> > it(newToolsMap);
    while (it.hasNext()) {
        it.next();
        QList<ExternalTool *> items;
        foreach (ExternalTool *tool, it.value()) {
            ExternalTool *toolToAdd = 0;
            if (ExternalTool *originalTool = originalTools.take(tool->id())) {
                // check if it has different category and is custom tool
                if (tool->displayCategory() != it.key() && !tool->preset())
                    tool->setDisplayCategory(it.key());
                // check if the tool has changed
                if ((*originalTool) == (*tool)) {
                    toolToAdd = originalTool;
                } else {
                    // case 1: tool is changed preset
                    if (tool->preset() && (*tool) != (*(tool->preset()))) {
                        // check if we need to choose a new file name
                        if (tool->preset()->fileName() == tool->fileName()) {
                            const QString &fileName = QFileInfo(tool->preset()->fileName()).fileName();
                            const QString &newFilePath = getUserFilePath(fileName);
                            // TODO error handling if newFilePath.isEmpty() (i.e. failed to find a unused name)
                            tool->setFileName(newFilePath);
                        }
                        // TODO error handling
                        tool->save();
                    // case 2: tool is previously changed preset but now same as preset
                    } else if (tool->preset() && (*tool) == (*(tool->preset()))) {
                        // check if we need to delete the changed description
                        if (originalTool->fileName() != tool->preset()->fileName()
                                && QFile::exists(originalTool->fileName())) {
                            // TODO error handling
                            QFile::remove(originalTool->fileName());
                        }
                        tool->setFileName(tool->preset()->fileName());
                        // no need to save, it's the same as the preset
                    // case 3: tool is custom tool
                    } else {
                        // TODO error handling
                        tool->save();
                    }

                     // 'tool' is deleted by config page, 'originalTool' is deleted by setToolsByCategory
                    toolToAdd = new ExternalTool(tool);
                }
            } else {
                // new tool. 'tool' is deleted by config page
                QString id = idFromDisplayName(tool->displayName());
                id = findUnusedId(id, newToolsMap);
                tool->setId(id);
                // TODO error handling if newFilePath.isEmpty() (i.e. failed to find a unused name)
                tool->setFileName(getUserFilePath(id + QLatin1String(".xml")));
                // TODO error handling
                tool->save();
                toolToAdd = new ExternalTool(tool);
            }
            items.append(toolToAdd);
        }
        if (!items.isEmpty())
            resultMap.insert(it.key(), items);
    }
    // Remove tools that have been deleted from the settings (and are no preset)
    foreach (ExternalTool *tool, originalTools) {
        QTC_ASSERT(!tool->preset(), continue);
        // TODO error handling
        QFile::remove(tool->fileName());
    }

    ExternalToolManager::setToolsByCategory(resultMap);
}

void ToolSettings::finish()
{
    delete m_widget;
}
<|endoftext|>


<commit_before>// Tests for gheap.
//
// Pass -DGHEAP_CPP11 to compiler for gheap_cpp11.hpp tests,
// otherwise gheap_cpp03.hpp will be tested.

#ifdef GHEAP_CPP11
#  include "gheap_cpp11.hpp"
#else
#  include "gheap_cpp03.hpp"
#endif

#include <cstdlib>    // for srand(), rand()
#include <iostream>   // for cout
#include <vector>

using namespace std;

namespace {

// Verifies correctness of parent and child index calculations.
template <size_t Fanout, size_t PageChunks>
void test_parent_child(const size_t start_index, const size_t n)
{
  assert(start_index > 0);
  assert(start_index <= SIZE_MAX - n);

  typedef gheap<Fanout, PageChunks> heap;

  for (size_t i = 0; i < n; ++i) {
    const size_t u = start_index + i;
    size_t v = heap::get_child_index(u);
    if (v < SIZE_MAX) {
      assert(v > u);
      v = heap::get_parent_index(v);
      assert(v == u);
    }

    v = heap::get_parent_index(u);
    assert(v < u);
    v = heap::get_child_index(v);
    assert(v <= u && u - v < Fanout);
  }

  cout << "test_parent_child(start_index=" << start_index << ", n=" << n <<
      ", Fanout=" << Fanout << ", PageChunks=" << PageChunks << ") OK" << endl;
}

// Verifies is_heap_until() and is_heap() correctness.
template <size_t Fanout, size_t PageChunks>
void test_is_heap(const size_t n)
{
  assert(n > 0);

  typedef gheap<Fanout, PageChunks> heap;

  vector<int> a;

  // Verify that ascending sorted array creates one-item heap.
  a.clear();
  for (size_t i = 0; i < n; ++i) {
    a.push_back(i);
  }
  assert(heap::is_heap_until(a.begin(), a.end()) == a.begin() + 1);
  assert(heap::is_heap(a.begin(), a.begin() + 1));
  if (n > 1) {
    assert(!heap::is_heap(a.begin(), a.end()));
  }

  // Verify that descending sorted array creates valid heap.
  a.clear();
  for (size_t i = 0; i < n; ++i) {
    a.push_back(n - i);
  }
  assert(heap::is_heap_until(a.begin(), a.end()) == a.end());
  assert(heap::is_heap(a.begin(), a.end()));

  // Verify that array containing identical items creates valid heap.
  a.clear();
  for (size_t i = 0; i < n; ++i) {
    a.push_back(n);
  }
  assert(heap::is_heap_until(a.begin(), a.end()) == a.end());
  assert(heap::is_heap(a.begin(), a.end()));
}

// Fills the given array with n random integers.
void init_array(vector<int> *const a, const size_t n)
{
  a->clear();
  a->reserve(n);

  srand(0);
  for (size_t i = 0; i < n; ++i) {
    a->push_back(rand());
  }
}

// Verifies that items in the given range are sorted in ascending order.
template <class RandomAccessIterator>
void assert_sorted_asc(const RandomAccessIterator &first,
    const RandomAccessIterator &last)
{
  assert(last > first);

  const size_t size = last - first;
  for (size_t i = 1; i < size; ++i) {
    assert(first[i] >= first[i - 1]);
  }
}

// Verifies that items in the given range are sorted in descending order.
template <class RandomAccessIterator>
void assert_sorted_desc(const RandomAccessIterator &first,
    const RandomAccessIterator &last)
{
  assert(last > first);

  const size_t size = last - first;
  for (size_t i = 1; i < size; ++i) {
    assert(first[i] <= first[i - 1]);
  }
}

bool inverse_less_comparer(const int a, const int b)
{
  return (b < a);
}

// Verifies correctness of heapsort built on top of "make_heap(); build_heap()".
template <size_t Fanout, size_t PageChunks>
void test_heapsort(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  vector<int> a;

  // Verify ascending sorting with default less_comparer.
  init_array(&a, n);
  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  heap::sort_heap(a.begin(), a.end());
  assert_sorted_asc(a.begin(), a.end());

  // Verify descending sorting with custom less_comparer.
  init_array(&a, n);
  heap::make_heap(a.begin(), a.end(), inverse_less_comparer);
  assert(heap::is_heap(a.begin(), a.end(), inverse_less_comparer));
  heap::sort_heap(a.begin(), a.end(), inverse_less_comparer);
  assert_sorted_desc(a.begin(), a.end());

  cout << "test_heapsort(n=" << n << ", Fanout=" << Fanout << ", PageChunks=" <<
      PageChunks << ") OK" << endl;
}

// Verifies push_heap() correctness.
template <size_t Fanout, size_t PageChunks>
void test_push_heap(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  vector<int> a;
  init_array(&a, n);

  for (size_t i = 0; i < n; ++i) {
    heap::push_heap(a.begin(), a.begin() + i + 1);
  }
  assert(heap::is_heap(a.begin(), a.end()));

  cout << "test_push_heap(n=" << n << ", Fanout=" << Fanout <<
      ", PageChunks=" << PageChunks << ") OK" << endl;
}

template <size_t Fanout, size_t PageChunks>
void test_pop_heap(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  vector<int> a;
  init_array(&a, n);

  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  for (size_t i = 0; i < n; ++i) {
    const int item = a[0];
    heap::pop_heap(a.begin(), a.end() - i);
    assert(item == *(a.end() - i - 1));
  }
  assert_sorted_asc(a.begin(), a.end());

  cout << "test_pop_heap(n=" << n << ", Fanout=" << Fanout <<
      ", PageChunks=" << PageChunks << ") OK" << endl;
}

// Verifies restore_heap_after_item_increase() correctness.
template <size_t Fanout, size_t PageChunks>
void test_restore_heap_after_item_increase(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  vector<int> a;
  init_array(&a, n);

  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  for (size_t i = 0; i < n; ++i) {
    const size_t item_index = rand() % n;
    const int old_item = a[item_index];

    // Don't allow integer overflow.
    size_t fade = SIZE_MAX;
    do {
      // Division by zero is impossible here.
      a[item_index] = old_item + rand() % fade;
      fade /= 2;
    } while (a[item_index] < old_item);
    heap::restore_heap_after_item_increase(a.begin(), a.begin() + item_index);
    assert(heap::is_heap(a.begin(), a.end()));
  }

  cout << "test_restore_heap_after_item_increase(n=" << n << ", Fanout=" <<
      Fanout << ", PageChunks=" << PageChunks << ") OK" << endl;
}

// Verifies restore_heap_after_item_decrease() correctness.
template <size_t Fanout, size_t PageChunks>
void test_restore_heap_after_item_decrease(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  vector<int> a;
  init_array(&a, n);

  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  for (size_t i = 0; i < n; ++i) {
    const size_t item_index = rand() % n;
    const int old_item = a[item_index];

    // Don't allow integer underflow.
    size_t fade = SIZE_MAX;
    do {
      // Division by zero is impossible here.
      a[item_index] = old_item - rand() % fade;
      fade /= 2;
    } while (a[item_index] > old_item);
    heap::restore_heap_after_item_decrease(a.begin(), a.begin() + item_index,
        a.end());
    assert(heap::is_heap(a.begin(), a.end()));
  }

  cout << "test_restore_heap_after_item_decrease(n=" << n << ", Fanout=" <<
      Fanout << ", PageChunks=" << PageChunks << ") OK" << endl;
}

template <size_t Fanout, size_t PageChunks>
void test_remove_from_heap(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  vector<int> a;
  init_array(&a, n);

  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  for (size_t i = 0; i < n; ++i) {
    const size_t item_index = rand() % (n - i);
    const int item = a[item_index];
    heap::remove_from_heap(a.begin(), a.begin() + item_index, a.end() - i);
    assert(heap::is_heap(a.begin(), a.end() - i - 1));
    assert(item == *(a.end() - i - 1));
  }

  cout << "test_remove_from_heap(n=" << n << ", Fanout=" << Fanout <<
      ", PageChunks=" << PageChunks << ") OK" << endl;
}

// Runs all tests for the given Fanout and PageChunks.
template <size_t Fanout, size_t PageChunks>
void test_all()
{
  // Verify parent-child calculations for indexes close to zero and
  // indexes close to SIZE_MAX.
  static const size_t n = 1000000;
  test_parent_child<Fanout, PageChunks>(1, n);
  test_parent_child<Fanout, PageChunks>(SIZE_MAX - n, n);

  test_is_heap<Fanout, PageChunks>(1);
  test_is_heap<Fanout, PageChunks>(2);
  test_is_heap<Fanout, PageChunks>(3);
  test_is_heap<Fanout, PageChunks>(1000);

  test_heapsort<Fanout, PageChunks>(1);
  test_heapsort<Fanout, PageChunks>(2);
  test_heapsort<Fanout, PageChunks>(3);
  // heapsort for Fanout = 1 is slow, so sort less items.
  test_heapsort<Fanout, PageChunks>(Fanout > 1 ? 100000 : 1000);

  test_push_heap<Fanout, PageChunks>(1);
  test_push_heap<Fanout, PageChunks>(2);
  test_push_heap<Fanout, PageChunks>(3);
  test_push_heap<Fanout, PageChunks>(1000);

  test_pop_heap<Fanout, PageChunks>(1);
  test_pop_heap<Fanout, PageChunks>(2);
  test_pop_heap<Fanout, PageChunks>(3);
  test_pop_heap<Fanout, PageChunks>(1000);

  test_restore_heap_after_item_increase<Fanout, PageChunks>(1);
  test_restore_heap_after_item_increase<Fanout, PageChunks>(2);
  test_restore_heap_after_item_increase<Fanout, PageChunks>(3);
  test_restore_heap_after_item_increase<Fanout, PageChunks>(1000);

  test_restore_heap_after_item_decrease<Fanout, PageChunks>(1);
  test_restore_heap_after_item_decrease<Fanout, PageChunks>(2);
  test_restore_heap_after_item_decrease<Fanout, PageChunks>(3);
  test_restore_heap_after_item_decrease<Fanout, PageChunks>(1000);

  test_remove_from_heap<Fanout, PageChunks>(1);
  test_remove_from_heap<Fanout, PageChunks>(2);
  test_remove_from_heap<Fanout, PageChunks>(3);
  test_remove_from_heap<Fanout, PageChunks>(1000);
}

}  // End of anonymous namespace.

int main()
{
  test_all<1, 1>();
  test_all<2, 1>();
  test_all<3, 1>();
  test_all<4, 1>();
  test_all<101, 1>();

  test_all<1, 2>();
  test_all<2, 2>();
  test_all<3, 2>();
  test_all<4, 2>();
  test_all<101, 2>();

  test_all<1, 3>();
  test_all<2, 3>();
  test_all<3, 3>();
  test_all<4, 3>();
  test_all<101, 3>();

  test_all<1, 4>();
  test_all<2, 4>();
  test_all<3, 4>();
  test_all<4, 4>();
  test_all<101, 4>();

  test_all<1, 101>();
  test_all<2, 101>();
  test_all<3, 101>();
  test_all<4, 101>();
  test_all<101, 101>();

  cout << "All tests DONE" << endl;
}
<commit_msg>added tests on top of STL deque<commit_after>// Tests for gheap.
//
// Pass -DGHEAP_CPP11 to compiler for gheap_cpp11.hpp tests,
// otherwise gheap_cpp03.hpp will be tested.

#ifdef GHEAP_CPP11
#  include "gheap_cpp11.hpp"
#else
#  include "gheap_cpp03.hpp"
#endif

#include <cstdlib>    // for srand(), rand()
#include <deque>
#include <iostream>   // for cout
#include <vector>

using namespace std;

namespace {

// Verifies correctness of parent and child index calculations.
template <size_t Fanout, size_t PageChunks>
void test_parent_child(const size_t start_index, const size_t n)
{
  assert(start_index > 0);
  assert(start_index <= SIZE_MAX - n);

  typedef gheap<Fanout, PageChunks> heap;

  cout << "    test_parent_child(start_index=" << start_index << ", n=" << n <<
      ") ";

  for (size_t i = 0; i < n; ++i) {
    const size_t u = start_index + i;
    size_t v = heap::get_child_index(u);
    if (v < SIZE_MAX) {
      assert(v > u);
      v = heap::get_parent_index(v);
      assert(v == u);
    }

    v = heap::get_parent_index(u);
    assert(v < u);
    v = heap::get_child_index(v);
    assert(v <= u && u - v < Fanout);
  }

  cout << "OK" << endl;
}

// Verifies is_heap_until() and is_heap() correctness.
template <size_t Fanout, size_t PageChunks, class IntContainer>
void test_is_heap(const size_t n)
{
  assert(n > 0);

  typedef gheap<Fanout, PageChunks> heap;

  cout << "    test_is_heap(n=" << n << ") ";

  IntContainer a;

  // Verify that ascending sorted array creates one-item heap.
  a.clear();
  for (size_t i = 0; i < n; ++i) {
    a.push_back(i);
  }
  assert(heap::is_heap_until(a.begin(), a.end()) == a.begin() + 1);
  assert(heap::is_heap(a.begin(), a.begin() + 1));
  if (n > 1) {
    assert(!heap::is_heap(a.begin(), a.end()));
  }

  // Verify that descending sorted array creates valid heap.
  a.clear();
  for (size_t i = 0; i < n; ++i) {
    a.push_back(n - i);
  }
  assert(heap::is_heap_until(a.begin(), a.end()) == a.end());
  assert(heap::is_heap(a.begin(), a.end()));

  // Verify that array containing identical items creates valid heap.
  a.clear();
  for (size_t i = 0; i < n; ++i) {
    a.push_back(n);
  }
  assert(heap::is_heap_until(a.begin(), a.end()) == a.end());
  assert(heap::is_heap(a.begin(), a.end()));

  cout << "OK" << endl;
}

// Fills the given array with n random integers.
template <class IntContainer>
void init_array(IntContainer *const a, const size_t n)
{
  a->clear();
//  a->reserve(n);

  srand(0);
  for (size_t i = 0; i < n; ++i) {
    a->push_back(rand());
  }
}

// Verifies that items in the given range are sorted in ascending order.
template <class RandomAccessIterator>
void assert_sorted_asc(const RandomAccessIterator &first,
    const RandomAccessIterator &last)
{
  assert(last > first);

  const size_t size = last - first;
  for (size_t i = 1; i < size; ++i) {
    assert(first[i] >= first[i - 1]);
  }
}

// Verifies that items in the given range are sorted in descending order.
template <class RandomAccessIterator>
void assert_sorted_desc(const RandomAccessIterator &first,
    const RandomAccessIterator &last)
{
  assert(last > first);

  const size_t size = last - first;
  for (size_t i = 1; i < size; ++i) {
    assert(first[i] <= first[i - 1]);
  }
}

bool inverse_less_comparer(const int a, const int b)
{
  return (b < a);
}

// Verifies correctness of heapsort built on top of "make_heap(); build_heap()".
template <size_t Fanout, size_t PageChunks, class IntContainer>
void test_heapsort(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  cout << "    test_heapsort(n=" << n << ") ";

  IntContainer a;

  // Verify ascending sorting with default less_comparer.
  init_array(&a, n);
  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  heap::sort_heap(a.begin(), a.end());
  assert_sorted_asc(a.begin(), a.end());

  // Verify descending sorting with custom less_comparer.
  init_array(&a, n);
  heap::make_heap(a.begin(), a.end(), inverse_less_comparer);
  assert(heap::is_heap(a.begin(), a.end(), inverse_less_comparer));
  heap::sort_heap(a.begin(), a.end(), inverse_less_comparer);
  assert_sorted_desc(a.begin(), a.end());

  cout << "OK" << endl;
}

// Verifies push_heap() correctness.
template <size_t Fanout, size_t PageChunks, class IntContainer>
void test_push_heap(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  cout << "    test_push_heap(n=" << n << ") ";

  IntContainer a;
  init_array(&a, n);

  for (size_t i = 0; i < n; ++i) {
    heap::push_heap(a.begin(), a.begin() + i + 1);
  }
  assert(heap::is_heap(a.begin(), a.end()));

  cout << "OK" << endl;
}

template <size_t Fanout, size_t PageChunks, class IntContainer>
void test_pop_heap(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  cout << "    test_pop_heap(n=" << n << ") ";

  IntContainer a;
  init_array(&a, n);

  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  for (size_t i = 0; i < n; ++i) {
    const int item = a[0];
    heap::pop_heap(a.begin(), a.end() - i);
    assert(item == *(a.end() - i - 1));
  }
  assert_sorted_asc(a.begin(), a.end());

  cout << "OK" << endl;
}

// Verifies restore_heap_after_item_increase() correctness.
template <size_t Fanout, size_t PageChunks, class IntContainer>
void test_restore_heap_after_item_increase(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  cout << "    test_restore_heap_after_item_increase(n=" << n << ") ";

  IntContainer a;
  init_array(&a, n);

  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  for (size_t i = 0; i < n; ++i) {
    const size_t item_index = rand() % n;
    const int old_item = a[item_index];

    // Don't allow integer overflow.
    size_t fade = SIZE_MAX;
    do {
      // Division by zero is impossible here.
      a[item_index] = old_item + rand() % fade;
      fade /= 2;
    } while (a[item_index] < old_item);
    heap::restore_heap_after_item_increase(a.begin(), a.begin() + item_index);
    assert(heap::is_heap(a.begin(), a.end()));
  }

  cout << "OK" << endl;
}

// Verifies restore_heap_after_item_decrease() correctness.
template <size_t Fanout, size_t PageChunks, class IntContainer>
void test_restore_heap_after_item_decrease(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  cout << "    test_resotre_heap_after_item_decrease(n=" << n << ") ";

  IntContainer a;
  init_array(&a, n);

  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  for (size_t i = 0; i < n; ++i) {
    const size_t item_index = rand() % n;
    const int old_item = a[item_index];

    // Don't allow integer underflow.
    size_t fade = SIZE_MAX;
    do {
      // Division by zero is impossible here.
      a[item_index] = old_item - rand() % fade;
      fade /= 2;
    } while (a[item_index] > old_item);
    heap::restore_heap_after_item_decrease(a.begin(), a.begin() + item_index,
        a.end());
    assert(heap::is_heap(a.begin(), a.end()));
  }

  cout << "OK" << endl;
}

// Verifies remove_from_heap() correctness.
template <size_t Fanout, size_t PageChunks, class IntContainer>
void test_remove_from_heap(const size_t n)
{
  typedef gheap<Fanout, PageChunks> heap;

  cout << "    test_remove_from_heap(n=" << n << ") ";

  IntContainer a;
  init_array(&a, n);

  heap::make_heap(a.begin(), a.end());
  assert(heap::is_heap(a.begin(), a.end()));
  for (size_t i = 0; i < n; ++i) {
    const size_t item_index = rand() % (n - i);
    const int item = a[item_index];
    heap::remove_from_heap(a.begin(), a.begin() + item_index, a.end() - i);
    assert(heap::is_heap(a.begin(), a.end() - i - 1));
    assert(item == *(a.end() - i - 1));
  }

  cout << "OK" << endl;
}

template <class Func>
void test_func(const Func &func)
{
  func(1);
  func(2);
  func(3);
  func(1001);
}

// Runs all gheap tests for the given Fanout and PageChunks.
template <size_t Fanout, size_t PageChunks, class IntContainer>
void test_all()
{
  cout << "  test_all(Fanout=" << Fanout << ", PageChunks=" << PageChunks <<
      ") start" << endl;

  // Verify parent-child calculations for indexes close to zero and
  // indexes close to SIZE_MAX.
  static const size_t n = 1000000;
  test_parent_child<Fanout, PageChunks>(1, n);
  test_parent_child<Fanout, PageChunks>(SIZE_MAX - n, n);

  test_func(test_is_heap<Fanout, PageChunks, IntContainer>);
  test_func(test_heapsort<Fanout, PageChunks, IntContainer>);
  test_func(test_push_heap<Fanout, PageChunks, IntContainer>);
  test_func(test_pop_heap<Fanout, PageChunks, IntContainer>);
  test_func(test_restore_heap_after_item_increase<Fanout, PageChunks,
      IntContainer>);
  test_func(test_restore_heap_after_item_decrease<Fanout, PageChunks,
      IntContainer>);
  test_func(test_remove_from_heap<Fanout, PageChunks, IntContainer>);

  cout << "  test_all(Fanout=" << Fanout << ", PageChunks=" << PageChunks <<
      ") OK" << endl;
}

// Runs all gheap tests on top of the given container with various Fanout
// and PageChunks values.
template <class IntContainer>
void main_test(const char *const container_name)
{
  cout << "main_test(" << container_name << ") start" << endl;

  test_all<1, 1, IntContainer>();
  test_all<2, 1, IntContainer>();
  test_all<3, 1, IntContainer>();
  test_all<4, 1, IntContainer>();
  test_all<101, 1, IntContainer>();

  test_all<1, 2, IntContainer>();
  test_all<2, 2, IntContainer>();
  test_all<3, 2, IntContainer>();
  test_all<4, 2, IntContainer>();
  test_all<101, 2, IntContainer>();

  test_all<1, 3, IntContainer>();
  test_all<2, 3, IntContainer>();
  test_all<3, 3, IntContainer>();
  test_all<4, 3, IntContainer>();
  test_all<101, 3, IntContainer>();

  test_all<1, 4, IntContainer>();
  test_all<2, 4, IntContainer>();
  test_all<3, 4, IntContainer>();
  test_all<4, 4, IntContainer>();
  test_all<101, 4, IntContainer>();

  test_all<1, 101, IntContainer>();
  test_all<2, 101, IntContainer>();
  test_all<3, 101, IntContainer>();
  test_all<4, 101, IntContainer>();
  test_all<101, 101, IntContainer>();

  cout << "main_test(" << container_name << ") OK" << endl;
}

}  // End of anonymous namespace.

int main()
{
  main_test<vector<int> >("vector");
  main_test<deque<int> >("deque");
}
<|endoftext|>


<commit_before>#include "drake/examples/Cars/car_simulation.h"

#include <cstdlib>

#include "drake/examples/Cars/curve2.h"
#include "drake/examples/Cars/gen/euler_floating_joint_state.h"
#include "drake/examples/Cars/gen/simple_car_state.h"
#include "drake/examples/Cars/trajectory_car.h"

using drake::AffineSystem;
using drake::NullVector;
using Eigen::Matrix;
using Eigen::MatrixXd;
using Eigen::VectorXd;

namespace drake {
namespace examples {
namespace cars {

const char kDurationFlag[] = "--duration";

void PrintUsageInstructions(const std::string& executable_name) {
  std::cout
    << "Usage: " << executable_name
    << " [vehicle model file] [world model files] "
    << kDurationFlag << " [duration in seconds]"
    << std::endl
    << std::endl
    << "Where:" << std::endl
    << "  - [vehicle model file] is the path to the URDF or SDF file defining"
    << std::endl
    << "    the vehicle model(s) and are thus attached to the world via"
    << std::endl
    << "    DrakeJoint::QUATERNION joints. This command line argument is"
    << std::endl
    << "    required."
    << std::endl
    << std::endl
    << "  - [world model files] is a space-separated list of paths to URDF or"
    << std::endl
    << "    SDF files. This list can be of length zero or more. The models"
    << std::endl
    << "    within these files are connected to the world via DrakeJoint::FIXED"
    << std::endl
    << "    joints. Since this list can have a length of zero, it is an"
    << std::endl
    << "    optional set of command line arguments."
    << std::endl
    << std::endl
    << "  - [duration in seconds] is the number of seconds (floating point) to"
    << std::endl
    << "    to run the simulation. This value is in simulation time, which is"
    << std::endl
    << "    not necessarily equal to real time. It is an optional argument that"
    << std::endl
    << "    follows an optional \"" << std::string(kDurationFlag) << "\" flag "
       "and be at the very end of"
    << std::endl
    << "    the command line argument list. If this flag and its argument are"
    << std::endl
    << "    not present, the duration is set to be infinity."
    << std::endl;
}

std::shared_ptr<RigidBodySystem> CreateRigidBodySystem(int argc,
                                                       const char* argv[],
                                                       double* duration) {
  if (argc < 2) {
    PrintUsageInstructions(argv[0]);
    exit(EXIT_FAILURE);
  }

  // Instantiates a rigid body system.
  auto rigid_body_sys = std::allocate_shared<RigidBodySystem>(
      Eigen::aligned_allocator<RigidBodySystem>());

  // Adds a robot model.
  rigid_body_sys->addRobotFromFile(argv[1], DrakeJoint::QUATERNION);

  if (duration != nullptr) {
    // Initializes duration to be infinity.
    *duration = std::numeric_limits<double>::infinity();
  }

  // Adds the environment.
  for (int ii = 2; ii < argc; ++ii) {
    if (std::string(argv[ii]) == "--duration") {
      if (++ii == argc) {
        throw std::runtime_error(
            "ERROR: Command line option \"--duration\" is not followed by a "
            "value!");
      }
      if (duration != nullptr)
        *duration = atof(argv[ii]);
    } else {
      rigid_body_sys->addRobotFromFile(argv[ii], DrakeJoint::FIXED);
    }
  }

  // Adds a flat terrain if no environment is specified.
  if (argc < 3) {
    const std::shared_ptr<RigidBodyTree>& tree =
        rigid_body_sys->getRigidBodyTree();
    AddFlatTerrain(tree);
  }

  // Sets various simulation parameters.
  SetRigidBodySystemParameters(rigid_body_sys.get());

  return rigid_body_sys;
}

void SetRigidBodySystemParameters(RigidBodySystem* rigid_body_sys) {
  rigid_body_sys->penetration_stiffness = 5000.0;
  rigid_body_sys->penetration_damping =
    rigid_body_sys->penetration_stiffness / 10.0;
  rigid_body_sys->friction_coefficient = 10.0;  // essentially infinite friction
}

double ParseDuration(int argc, const char* argv[]) {
  for (int ii = 1; ii < argc; ++ii) {
    if (std::string(argv[ii]) == kDurationFlag) {
      if (++ii == argc) {
        PrintUsageInstructions(argv[0]);
        throw std::runtime_error(
            "ERROR: Command line option \"" + std::string(kDurationFlag) +
            "\" is not followed by a value!");
      }
      return atof(argv[ii]);
    }
  }
  return std::numeric_limits<double>::infinity();
}

void AddFlatTerrain(const std::shared_ptr<RigidBodyTree>& rigid_body_tree,
    double box_size, double box_depth) {
  DrakeShapes::Box geom(Eigen::Vector3d(box_size, box_size, box_depth));
  Eigen::Isometry3d T_element_to_link = Eigen::Isometry3d::Identity();
  T_element_to_link.translation() << 0, 0,
      -box_depth / 2;  // top of the box is at z=0
  RigidBody& world = rigid_body_tree->world();
  Eigen::Vector4d color;
  color << 0.9297, 0.7930, 0.6758,
      1;  // was hex2dec({'ee','cb','ad'})'/256 in matlab
  world.AddVisualElement(
      DrakeShapes::VisualElement(geom, T_element_to_link, color));
  rigid_body_tree->addCollisionElement(
      RigidBodyCollisionElement(geom, T_element_to_link, &world), world,
      "terrain");
  rigid_body_tree->updateStaticCollisionElements();
}

std::shared_ptr<CascadeSystem<
    Gain<DrivingCommand, PDControlSystem<RigidBodySystem>::InputVector>,
    PDControlSystem<RigidBodySystem>>>
CreateVehicleSystem(std::shared_ptr<RigidBodySystem> rigid_body_sys) {
  const auto& tree = rigid_body_sys->getRigidBodyTree();

  // Sets up PD controllers for throttle and steering.
  const double kpSteering = 400, kdSteering = 80, kThrottle = 100;

  MatrixXd Kp(getNumInputs(*rigid_body_sys), tree->number_of_positions());
  Kp.setZero();

  MatrixXd Kd(getNumInputs(*rigid_body_sys), tree->number_of_velocities());
  Kd.setZero();

  Matrix<double, Eigen::Dynamic, 3> map_driving_cmd_to_x_d(
      tree->number_of_positions() + tree->number_of_velocities(), 3);
  map_driving_cmd_to_x_d.setZero();

  for (int actuator_idx = 0;
       actuator_idx < static_cast<int>(tree->actuators.size());
       actuator_idx++) {
    const std::string& actuator_name = tree->actuators[actuator_idx].name_;

    if (actuator_name == "steering") {
      // Obtains the rigid body to which the actuator is attached.
      const auto& rigid_body = tree->actuators[actuator_idx].body_;

      // Sets the steering actuator's Kp gain.
      Kp(actuator_idx, rigid_body->get_position_start_index()) = kpSteering;

      // Sets the steering actuator's Kd gain.
      Kd(actuator_idx, rigid_body->get_velocity_start_index()) = kdSteering;

      // Saves the mapping between the driving command and the steering command.
      map_driving_cmd_to_x_d(rigid_body->get_position_start_index(),
                             DrivingCommandIndices::kSteeringAngle) =
          1;  // steering command

    } else if (actuator_name == "right_wheel_joint" ||
               actuator_name == "left_wheel_joint") {
      // Obtains the rigid body to which the actuator is attached.
      const auto& rigid_body = tree->actuators[actuator_idx].body_;

      // Sets the throttle Kd gain.
      Kd(actuator_idx, rigid_body->get_velocity_start_index()) = kThrottle;

      // Saves the mapping between the driving command and the throttle command.
      map_driving_cmd_to_x_d(
          tree->number_of_positions() + rigid_body->get_velocity_start_index(),
          DrivingCommandIndices::kThrottle) = 20;

      // Saves the mapping between the driving command and the braking command.
      map_driving_cmd_to_x_d(
          tree->number_of_positions() + rigid_body->get_velocity_start_index(),
          DrivingCommandIndices::kBrake) = -20;
    }
  }

  auto vehicle_with_pd = std::allocate_shared<PDControlSystem<RigidBodySystem>>(
      Eigen::aligned_allocator<PDControlSystem<RigidBodySystem>>(),
      rigid_body_sys, Kp, Kd);

  auto vehicle_sys = cascade(
      std::allocate_shared<
          Gain<DrivingCommand, PDControlSystem<RigidBodySystem>::InputVector>>(
          Eigen::aligned_allocator<Gain<
              DrivingCommand, PDControlSystem<RigidBodySystem>::InputVector>>(),
          map_driving_cmd_to_x_d),
      vehicle_with_pd);

  return vehicle_sys;
}

namespace {
// A figure-eight.  One loop has a radius of @p radius - @p inset,
// the other loop has a radius of @p radius + @p inset.
Curve2<double> MakeCurve(double radius, double inset) {
  // TODO(jwnimmer-tri) This function will be rewritten once we have
  // proper splines.  Don't try too hard to understand it.  Run the
  // demo to see it first, and only then try to understand the code.

  typedef Curve2<double>::Point2 Point2d;
  std::vector<Point2d> waypoints;

  // Start (0, +i).
  // Straight right to (+r, +i).
  // Loop around (+i, +r).
  // Straight back to (+i, 0).
  waypoints.push_back({0.0, inset});
  for (int theta_deg = -90; theta_deg <= 180; ++theta_deg) {
    const Point2d center{radius, radius};
    const double theta = theta_deg * M_PI / 180.0;
    const Point2d direction{std::cos(theta), std::sin(theta)};
    waypoints.push_back(center + (direction * (radius - inset)));
  }
  waypoints.push_back({inset, 0.0});

  // Start (+i, 0).
  // Straight down to (+i, -r).
  // Loop around (-r, +i).
  // Straight back to start (implicitly via segment to waypoints[0]).
  for (int theta_deg = 0; theta_deg >= -270; --theta_deg) {
    const Point2d center{-radius, -radius};
    const double theta = theta_deg * M_PI / 180.0;
    const Point2d direction{std::cos(theta), std::sin(theta)};
    waypoints.push_back(center + (direction * (radius + inset)));
  }

  // Many copies.
  const int kNumCopies = 100;
  std::vector<Point2d> looped_waypoints;
  for (int copies = 0; copies < kNumCopies; ++copies) {
    std::copy(waypoints.begin(), waypoints.end(),
              std::back_inserter(looped_waypoints));
  }
  looped_waypoints.push_back(waypoints.front());

  return Curve2<double>(looped_waypoints);
}
}  // namespace anonymous

std::shared_ptr<TrajectoryCar> CreateTrajectoryCarSystem(int index) {
  // The possible curves to trace (lanes).
  const std::vector<Curve2<double>> curves{
    MakeCurve(40.0, 0.0),  // BR
    MakeCurve(40.0, 4.0),  // BR
    MakeCurve(40.0, 8.0),
  };

  // Magic car placement to make a good visual demo.
  const auto& curve = curves[index % curves.size()];
  const double start_time = (index / curves.size()) * 0.8;
  const double kSpeed = 8.0;
  return std::make_shared<TrajectoryCar>(curve, kSpeed, start_time);
}

std::shared_ptr<AffineSystem<
  NullVector, SimpleCarState, EulerFloatingJointState>>
CreateSimpleCarVisualizationAdapter() {
  const int insize = SimpleCarState<double>().size();
  const int outsize = EulerFloatingJointState<double>().size();
  MatrixXd D;
  D.setZero(outsize, insize);
  D(EulerFloatingJointStateIndices::kX, SimpleCarStateIndices::kX) = 1;
  D(EulerFloatingJointStateIndices::kY, SimpleCarStateIndices::kY) = 1;
  D(EulerFloatingJointStateIndices::kYaw, SimpleCarStateIndices::kHeading) = 1;
  EulerFloatingJointState<double> y0;
  return std::make_shared<
    AffineSystem<
        NullVector,
        SimpleCarState,
        EulerFloatingJointState>>(
            MatrixXd::Zero(0, 0),
            MatrixXd::Zero(0, insize),
            VectorXd::Zero(0),
            MatrixXd::Zero(outsize, 0),
            D, toEigen(y0));
}

SimulationOptions GetCarSimulationDefaultOptions() {
  SimulationOptions result;
  result.initial_step_size = 5e-3;
  result.timeout_seconds = std::numeric_limits<double>::infinity();
  return result;
}

VectorXd GetInitialState(const RigidBodySystem& rigid_body_sys) {
  const auto& tree = rigid_body_sys.getRigidBodyTree();

  VectorXd x0 = VectorXd::Zero(rigid_body_sys.getNumStates());
  x0.head(tree->number_of_positions()) = tree->getZeroConfiguration();
  return x0;
}

}  // namespace cars
}  // namespace examples
}  // namespace drake
<commit_msg>Updated usage instructions.<commit_after>#include "drake/examples/Cars/car_simulation.h"

#include <cstdlib>

#include "drake/examples/Cars/curve2.h"
#include "drake/examples/Cars/gen/euler_floating_joint_state.h"
#include "drake/examples/Cars/gen/simple_car_state.h"
#include "drake/examples/Cars/trajectory_car.h"

using drake::AffineSystem;
using drake::NullVector;
using Eigen::Matrix;
using Eigen::MatrixXd;
using Eigen::VectorXd;

namespace drake {
namespace examples {
namespace cars {

const char kDurationFlag[] = "--duration";

void PrintUsageInstructions(const std::string& executable_name) {
  std::cout
    << "Usage: " << executable_name
    << " vehicle_model_file [world_model_files] ["
    << kDurationFlag << " duration_in_seconds]"
    << std::endl
    << std::endl
    << "Where:" << std::endl
    << "  - vehicle_model_file is the path to the URDF or SDF file defining"
    << std::endl
    << "    the vehicle model(s) and are thus attached to the world via"
    << std::endl
    << "    DrakeJoint::QUATERNION joints."
    << std::endl
    << std::endl
    << "  - world_model_files is a space-separated list of paths to URDF or"
    << std::endl
    << "    SDF files. This list can be of length zero or more. The models"
    << std::endl
    << "    within these files are connected to the world via DrakeJoint::FIXED"
    << std::endl
    << "    joints."
    << std::endl
    << std::endl
    << "  - duration_in_seconds is the number of seconds (floating point) to"
    << std::endl
    << "    to run the simulation. This value is in simulation time."
    << std::endl;
}

std::shared_ptr<RigidBodySystem> CreateRigidBodySystem(int argc,
                                                       const char* argv[],
                                                       double* duration) {
  if (argc < 2) {
    PrintUsageInstructions(argv[0]);
    exit(EXIT_FAILURE);
  }

  // Instantiates a rigid body system.
  auto rigid_body_sys = std::allocate_shared<RigidBodySystem>(
      Eigen::aligned_allocator<RigidBodySystem>());

  // Adds a robot model.
  rigid_body_sys->addRobotFromFile(argv[1], DrakeJoint::QUATERNION);

  if (duration != nullptr) {
    // Initializes duration to be infinity.
    *duration = std::numeric_limits<double>::infinity();
  }

  // Adds the environment.
  for (int ii = 2; ii < argc; ++ii) {
    if (std::string(argv[ii]) == "--duration") {
      if (++ii == argc) {
        throw std::runtime_error(
            "ERROR: Command line option \"--duration\" is not followed by a "
            "value!");
      }
      if (duration != nullptr)
        *duration = atof(argv[ii]);
    } else {
      rigid_body_sys->addRobotFromFile(argv[ii], DrakeJoint::FIXED);
    }
  }

  // Adds a flat terrain if no environment is specified.
  if (argc < 3) {
    const std::shared_ptr<RigidBodyTree>& tree =
        rigid_body_sys->getRigidBodyTree();
    AddFlatTerrain(tree);
  }

  // Sets various simulation parameters.
  SetRigidBodySystemParameters(rigid_body_sys.get());

  return rigid_body_sys;
}

void SetRigidBodySystemParameters(RigidBodySystem* rigid_body_sys) {
  rigid_body_sys->penetration_stiffness = 5000.0;
  rigid_body_sys->penetration_damping =
    rigid_body_sys->penetration_stiffness / 10.0;
  rigid_body_sys->friction_coefficient = 10.0;  // essentially infinite friction
}

double ParseDuration(int argc, const char* argv[]) {
  for (int ii = 1; ii < argc; ++ii) {
    if (std::string(argv[ii]) == kDurationFlag) {
      if (++ii == argc) {
        PrintUsageInstructions(argv[0]);
        throw std::runtime_error(
            "ERROR: Command line option \"" + std::string(kDurationFlag) +
            "\" is not followed by a value!");
      }
      return atof(argv[ii]);
    }
  }
  return std::numeric_limits<double>::infinity();
}

void AddFlatTerrain(const std::shared_ptr<RigidBodyTree>& rigid_body_tree,
    double box_size, double box_depth) {
  DrakeShapes::Box geom(Eigen::Vector3d(box_size, box_size, box_depth));
  Eigen::Isometry3d T_element_to_link = Eigen::Isometry3d::Identity();
  T_element_to_link.translation() << 0, 0,
      -box_depth / 2;  // top of the box is at z=0
  RigidBody& world = rigid_body_tree->world();
  Eigen::Vector4d color;
  color << 0.9297, 0.7930, 0.6758,
      1;  // was hex2dec({'ee','cb','ad'})'/256 in matlab
  world.AddVisualElement(
      DrakeShapes::VisualElement(geom, T_element_to_link, color));
  rigid_body_tree->addCollisionElement(
      RigidBodyCollisionElement(geom, T_element_to_link, &world), world,
      "terrain");
  rigid_body_tree->updateStaticCollisionElements();
}

std::shared_ptr<CascadeSystem<
    Gain<DrivingCommand, PDControlSystem<RigidBodySystem>::InputVector>,
    PDControlSystem<RigidBodySystem>>>
CreateVehicleSystem(std::shared_ptr<RigidBodySystem> rigid_body_sys) {
  const auto& tree = rigid_body_sys->getRigidBodyTree();

  // Sets up PD controllers for throttle and steering.
  const double kpSteering = 400, kdSteering = 80, kThrottle = 100;

  MatrixXd Kp(getNumInputs(*rigid_body_sys), tree->number_of_positions());
  Kp.setZero();

  MatrixXd Kd(getNumInputs(*rigid_body_sys), tree->number_of_velocities());
  Kd.setZero();

  Matrix<double, Eigen::Dynamic, 3> map_driving_cmd_to_x_d(
      tree->number_of_positions() + tree->number_of_velocities(), 3);
  map_driving_cmd_to_x_d.setZero();

  for (int actuator_idx = 0;
       actuator_idx < static_cast<int>(tree->actuators.size());
       actuator_idx++) {
    const std::string& actuator_name = tree->actuators[actuator_idx].name_;

    if (actuator_name == "steering") {
      // Obtains the rigid body to which the actuator is attached.
      const auto& rigid_body = tree->actuators[actuator_idx].body_;

      // Sets the steering actuator's Kp gain.
      Kp(actuator_idx, rigid_body->get_position_start_index()) = kpSteering;

      // Sets the steering actuator's Kd gain.
      Kd(actuator_idx, rigid_body->get_velocity_start_index()) = kdSteering;

      // Saves the mapping between the driving command and the steering command.
      map_driving_cmd_to_x_d(rigid_body->get_position_start_index(),
                             DrivingCommandIndices::kSteeringAngle) =
          1;  // steering command

    } else if (actuator_name == "right_wheel_joint" ||
               actuator_name == "left_wheel_joint") {
      // Obtains the rigid body to which the actuator is attached.
      const auto& rigid_body = tree->actuators[actuator_idx].body_;

      // Sets the throttle Kd gain.
      Kd(actuator_idx, rigid_body->get_velocity_start_index()) = kThrottle;

      // Saves the mapping between the driving command and the throttle command.
      map_driving_cmd_to_x_d(
          tree->number_of_positions() + rigid_body->get_velocity_start_index(),
          DrivingCommandIndices::kThrottle) = 20;

      // Saves the mapping between the driving command and the braking command.
      map_driving_cmd_to_x_d(
          tree->number_of_positions() + rigid_body->get_velocity_start_index(),
          DrivingCommandIndices::kBrake) = -20;
    }
  }

  auto vehicle_with_pd = std::allocate_shared<PDControlSystem<RigidBodySystem>>(
      Eigen::aligned_allocator<PDControlSystem<RigidBodySystem>>(),
      rigid_body_sys, Kp, Kd);

  auto vehicle_sys = cascade(
      std::allocate_shared<
          Gain<DrivingCommand, PDControlSystem<RigidBodySystem>::InputVector>>(
          Eigen::aligned_allocator<Gain<
              DrivingCommand, PDControlSystem<RigidBodySystem>::InputVector>>(),
          map_driving_cmd_to_x_d),
      vehicle_with_pd);

  return vehicle_sys;
}

namespace {
// A figure-eight.  One loop has a radius of @p radius - @p inset,
// the other loop has a radius of @p radius + @p inset.
Curve2<double> MakeCurve(double radius, double inset) {
  // TODO(jwnimmer-tri) This function will be rewritten once we have
  // proper splines.  Don't try too hard to understand it.  Run the
  // demo to see it first, and only then try to understand the code.

  typedef Curve2<double>::Point2 Point2d;
  std::vector<Point2d> waypoints;

  // Start (0, +i).
  // Straight right to (+r, +i).
  // Loop around (+i, +r).
  // Straight back to (+i, 0).
  waypoints.push_back({0.0, inset});
  for (int theta_deg = -90; theta_deg <= 180; ++theta_deg) {
    const Point2d center{radius, radius};
    const double theta = theta_deg * M_PI / 180.0;
    const Point2d direction{std::cos(theta), std::sin(theta)};
    waypoints.push_back(center + (direction * (radius - inset)));
  }
  waypoints.push_back({inset, 0.0});

  // Start (+i, 0).
  // Straight down to (+i, -r).
  // Loop around (-r, +i).
  // Straight back to start (implicitly via segment to waypoints[0]).
  for (int theta_deg = 0; theta_deg >= -270; --theta_deg) {
    const Point2d center{-radius, -radius};
    const double theta = theta_deg * M_PI / 180.0;
    const Point2d direction{std::cos(theta), std::sin(theta)};
    waypoints.push_back(center + (direction * (radius + inset)));
  }

  // Many copies.
  const int kNumCopies = 100;
  std::vector<Point2d> looped_waypoints;
  for (int copies = 0; copies < kNumCopies; ++copies) {
    std::copy(waypoints.begin(), waypoints.end(),
              std::back_inserter(looped_waypoints));
  }
  looped_waypoints.push_back(waypoints.front());

  return Curve2<double>(looped_waypoints);
}
}  // namespace anonymous

std::shared_ptr<TrajectoryCar> CreateTrajectoryCarSystem(int index) {
  // The possible curves to trace (lanes).
  const std::vector<Curve2<double>> curves{
    MakeCurve(40.0, 0.0),  // BR
    MakeCurve(40.0, 4.0),  // BR
    MakeCurve(40.0, 8.0),
  };

  // Magic car placement to make a good visual demo.
  const auto& curve = curves[index % curves.size()];
  const double start_time = (index / curves.size()) * 0.8;
  const double kSpeed = 8.0;
  return std::make_shared<TrajectoryCar>(curve, kSpeed, start_time);
}

std::shared_ptr<AffineSystem<
  NullVector, SimpleCarState, EulerFloatingJointState>>
CreateSimpleCarVisualizationAdapter() {
  const int insize = SimpleCarState<double>().size();
  const int outsize = EulerFloatingJointState<double>().size();
  MatrixXd D;
  D.setZero(outsize, insize);
  D(EulerFloatingJointStateIndices::kX, SimpleCarStateIndices::kX) = 1;
  D(EulerFloatingJointStateIndices::kY, SimpleCarStateIndices::kY) = 1;
  D(EulerFloatingJointStateIndices::kYaw, SimpleCarStateIndices::kHeading) = 1;
  EulerFloatingJointState<double> y0;
  return std::make_shared<
    AffineSystem<
        NullVector,
        SimpleCarState,
        EulerFloatingJointState>>(
            MatrixXd::Zero(0, 0),
            MatrixXd::Zero(0, insize),
            VectorXd::Zero(0),
            MatrixXd::Zero(outsize, 0),
            D, toEigen(y0));
}

SimulationOptions GetCarSimulationDefaultOptions() {
  SimulationOptions result;
  result.initial_step_size = 5e-3;
  result.timeout_seconds = std::numeric_limits<double>::infinity();
  return result;
}

VectorXd GetInitialState(const RigidBodySystem& rigid_body_sys) {
  const auto& tree = rigid_body_sys.getRigidBodyTree();

  VectorXd x0 = VectorXd::Zero(rigid_body_sys.getNumStates());
  x0.head(tree->number_of_positions()) = tree->getZeroConfiguration();
  return x0;
}

}  // namespace cars
}  // namespace examples
}  // namespace drake
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: svdoutl.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 16:45:46 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SVDOUTL_HXX //autogen
#include "svdoutl.hxx"
#endif
#ifndef _OUTLINER_HXX //autogen
#include "outliner.hxx"
#endif
#ifndef _SVDOTEXT_HXX //autogen
#include "svdotext.hxx"
#endif
#ifndef _EDITSTAT_HXX //autogen wg. EE_CNTRL_STRETCHING
#include <editstat.hxx>
#endif
#ifndef _SVDMODEL_HXX //autogen wg. SdrModel
#include <svdmodel.hxx>
#endif
#ifndef _EEITEM_HXX //autogen wg. EE_ITEMS_START
#include <eeitem.hxx>
#endif
#ifndef _SFXITEMPOOL_HXX //autogen wg. SfxItemPool
#include <svtools/itempool.hxx>
#endif

//TYPEINIT1( SdrOutliner, Outliner );

/*************************************************************************
|*
|* Ctor
|*
\************************************************************************/
SdrOutliner::SdrOutliner( SfxItemPool* pItemPool, USHORT nMode )
:   Outliner( pItemPool, nMode ),
    mpPaintInfoRec( NULL )
{
}

/*************************************************************************
|*
|* Dtor
|*
\************************************************************************/
SdrOutliner::~SdrOutliner()
{
}

/*************************************************************************
|*
|*
|*
\************************************************************************/
void SdrOutliner::SetTextObj( const SdrTextObj* pObj )
{
    if( pObj && pObj != mpTextObj.get() )
    {
        SetUpdateMode(FALSE);
        USHORT nOutlinerMode2 = OUTLINERMODE_OUTLINEOBJECT;
        if ( !pObj->IsOutlText() )
            nOutlinerMode2 = OUTLINERMODE_TEXTOBJECT;
        Init( nOutlinerMode2 );

        SetGlobalCharStretching(100,100);

        ULONG nStat = GetControlWord();
        nStat &= ~( EE_CNTRL_STRETCHING | EE_CNTRL_AUTOPAGESIZE );
        SetControlWord(nStat);

        Size aNullSize;
        Size aMaxSize( 100000,100000 );
        SetMinAutoPaperSize( aNullSize );
        SetMaxAutoPaperSize( aMaxSize );
        SetPaperSize( aMaxSize );
        ClearPolygon();
    }

    mpTextObj.reset( const_cast< SdrTextObj* >(pObj) );
}

/*************************************************************************
|*
|*
|*
\************************************************************************/
void SdrOutliner::SetTextObjNoInit( const SdrTextObj* pObj )
{
    mpTextObj.reset( const_cast< SdrTextObj* >(pObj) );
}

/*************************************************************************
|*
|*
|*
\************************************************************************/
XubString SdrOutliner::CalcFieldValue(const SvxFieldItem& rField, USHORT nPara, USHORT nPos,
                                     Color*& rpTxtColor, Color*& rpFldColor)
{
    FASTBOOL bOk = FALSE;
    XubString aRet;

    if(mpTextObj.is())
        bOk = static_cast< SdrTextObj* >( mpTextObj.get())->CalcFieldValue(rField, nPara, nPos, FALSE, rpTxtColor, rpFldColor, aRet);

    if (!bOk)
        aRet = Outliner::CalcFieldValue(rField, nPara, nPos, rpTxtColor, rpFldColor);

    return aRet;
}

const SdrTextObj* SdrOutliner::GetTextObj() const
{
    return static_cast< SdrTextObj* >( mpTextObj.get() );
}

<commit_msg>INTEGRATION: CWS pchfix02 (1.6.114); FILE MERGED 2006/09/01 17:47:27 kaib 1.6.114.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: svdoutl.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 05:58:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#ifndef _SVDOUTL_HXX //autogen
#include "svdoutl.hxx"
#endif
#ifndef _OUTLINER_HXX //autogen
#include "outliner.hxx"
#endif
#ifndef _SVDOTEXT_HXX //autogen
#include "svdotext.hxx"
#endif
#ifndef _EDITSTAT_HXX //autogen wg. EE_CNTRL_STRETCHING
#include <editstat.hxx>
#endif
#ifndef _SVDMODEL_HXX //autogen wg. SdrModel
#include <svdmodel.hxx>
#endif
#ifndef _EEITEM_HXX //autogen wg. EE_ITEMS_START
#include <eeitem.hxx>
#endif
#ifndef _SFXITEMPOOL_HXX //autogen wg. SfxItemPool
#include <svtools/itempool.hxx>
#endif

//TYPEINIT1( SdrOutliner, Outliner );

/*************************************************************************
|*
|* Ctor
|*
\************************************************************************/
SdrOutliner::SdrOutliner( SfxItemPool* pItemPool, USHORT nMode )
:   Outliner( pItemPool, nMode ),
    mpPaintInfoRec( NULL )
{
}

/*************************************************************************
|*
|* Dtor
|*
\************************************************************************/
SdrOutliner::~SdrOutliner()
{
}

/*************************************************************************
|*
|*
|*
\************************************************************************/
void SdrOutliner::SetTextObj( const SdrTextObj* pObj )
{
    if( pObj && pObj != mpTextObj.get() )
    {
        SetUpdateMode(FALSE);
        USHORT nOutlinerMode2 = OUTLINERMODE_OUTLINEOBJECT;
        if ( !pObj->IsOutlText() )
            nOutlinerMode2 = OUTLINERMODE_TEXTOBJECT;
        Init( nOutlinerMode2 );

        SetGlobalCharStretching(100,100);

        ULONG nStat = GetControlWord();
        nStat &= ~( EE_CNTRL_STRETCHING | EE_CNTRL_AUTOPAGESIZE );
        SetControlWord(nStat);

        Size aNullSize;
        Size aMaxSize( 100000,100000 );
        SetMinAutoPaperSize( aNullSize );
        SetMaxAutoPaperSize( aMaxSize );
        SetPaperSize( aMaxSize );
        ClearPolygon();
    }

    mpTextObj.reset( const_cast< SdrTextObj* >(pObj) );
}

/*************************************************************************
|*
|*
|*
\************************************************************************/
void SdrOutliner::SetTextObjNoInit( const SdrTextObj* pObj )
{
    mpTextObj.reset( const_cast< SdrTextObj* >(pObj) );
}

/*************************************************************************
|*
|*
|*
\************************************************************************/
XubString SdrOutliner::CalcFieldValue(const SvxFieldItem& rField, USHORT nPara, USHORT nPos,
                                     Color*& rpTxtColor, Color*& rpFldColor)
{
    FASTBOOL bOk = FALSE;
    XubString aRet;

    if(mpTextObj.is())
        bOk = static_cast< SdrTextObj* >( mpTextObj.get())->CalcFieldValue(rField, nPara, nPos, FALSE, rpTxtColor, rpFldColor, aRet);

    if (!bOk)
        aRet = Outliner::CalcFieldValue(rField, nPara, nPos, rpTxtColor, rpFldColor);

    return aRet;
}

const SdrTextObj* SdrOutliner::GetTextObj() const
{
    return static_cast< SdrTextObj* >( mpTextObj.get() );
}

<|endoftext|>


<commit_before><commit_msg>cambiada regex de nombre de participante<commit_after><|endoftext|>