text:
#include "postgres.h"

#include <signal.h>
#include <time.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include "cdb/cdbselect.h"

#ifdef WIN32
#include "win32.h"
#else
#include <unistd.h>
#include <sys/time.h>
#endif

#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif

#include "gp-libpq-fe.h"
#include "gp-libpq-int.h"
#include "libpq/pqsignal.h"
#include "mb/pg_wchar.h"
#include "pg_config_paths.h"

#include "utils/hsearch.h"
#include "nodes/pg_list.h"
#include "cdb/cdbpartition.h"

static int pqPutMsgBytes(const void *buf, size_t len, PGconn *conn);
static int pqSendSome(PGconn *conn, int len);
static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time);
static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time);

/*
 * fputnbytes: print exactly N bytes to a file
 *
 * We avoid using %.*s here because it can misbehave if the data
 * is not valid in what libc thinks is the prevailing encoding.
 */
static void
fputnbytes(FILE *f, const char *str, size_t n)
{
	while (n-- > 0)
		fputc(*str++, f);
}

/*
 * pqGetc: get 1 character from the connection
 *
 *	All these routines return 0 on success, EOF on error.
 *	Note that for the Get routines, EOF only means there is not enough
 *	data in the buffer, not that there is necessarily a hard error.
 */
int
pqGetc(char *result, PGconn *conn)
{
	if (conn->inCursor >= conn->inEnd)
		return EOF;

	*result = conn->inBuffer[conn->inCursor++];

	if (conn->Pfdebug)
		fprintf(conn->Pfdebug, "From backend> %c\n", *result);

	return 0;
}

/*
 * pqPutc: write 1 char to the current message
 */
int
pqPutc(char c, PGconn *conn)
{
	if (pqPutMsgBytes(&c, 1, conn))
		return EOF;

	if (conn->Pfdebug)
		fprintf(conn->Pfdebug, "To backend> %c\n", c);

	return 0;
}

/*
 * pqGets[_append]:
 * get a null-terminated string from the connection,
 * and store it in an expansible PQExpBuffer.
 * If we run out of memory, all of the string is still read,
 * but the excess characters are silently discarded.
 */
static int
pqGets_internal(PQExpBuffer buf, PGconn *conn, bool resetbuffer)
{
	/* Copy conn data to locals for faster search loop */
	char	   *inBuffer = conn->inBuffer;
	int			inCursor = conn->inCursor;
	int			inEnd = conn->inEnd;
	int			slen;

	while (inCursor < inEnd && inBuffer[inCursor])
		inCursor++;

	if (inCursor >= inEnd)
		return EOF;

	slen = inCursor - conn->inCursor;

	if (resetbuffer)
	resetPQExpBuffer(buf);

	appendBinaryPQExpBuffer(buf, inBuffer + conn->inCursor, slen);

	conn->inCursor = ++inCursor;

	if (conn->Pfdebug)
		fprintf(conn->Pfdebug, "From backend> \"%s\"\n",
				buf->data);

	return 0;
}

int
pqGets(PQExpBuffer buf, PGconn *conn)
{
	return pqGets_internal(buf, conn, true);
}

int
pqGets_append(PQExpBuffer buf, PGconn *conn)
{
	return pqGets_internal(buf, conn, false);
}

/*
 * pqPuts: write a null-terminated string to the current message
 */
int
pqPuts(const char *s, PGconn *conn)
{
	if (pqPutMsgBytes(s, strlen(s) + 1, conn))
		return EOF;

	if (conn->Pfdebug)
		fprintf(conn->Pfdebug, "To backend> \"%s\"\n", s);

	return 0;
}

/*
 * pqGetnchar:
 *	get a string of exactly len bytes in buffer s, no null termination
 */
int
pqGetnchar(char *s, size_t len, PGconn *conn)
{
	if ((long)len < 0 || len > (size_t) (conn->inEnd - conn->inCursor))
		return EOF;

	memcpy(s, conn->inBuffer + conn->inCursor, len);
	/* no terminating null */

	conn->inCursor += len;

	if (conn->Pfdebug)
	{
		fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len);
		fputnbytes(conn->Pfdebug, s, len);
		fprintf(conn->Pfdebug, "\n");
	}

	return 0;
}

/*
 * pqSkipnchar:
 *	skip over len bytes in input buffer.
 *
 * Note: this is primarily useful for its debug output, which should
 * be exactly the same as for pqGetnchar.  We assume the data in question
 * will actually be used, but just isn't getting copied anywhere as yet.
 */
int
pqSkipnchar(size_t len, PGconn *conn)
{
	if (len > (size_t) (conn->inEnd - conn->inCursor))
		return EOF;

	if (conn->Pfdebug)
	{
		fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len);
		fputnbytes(conn->Pfdebug, conn->inBuffer + conn->inCursor, len);
		fprintf(conn->Pfdebug, "\n");
	}

	conn->inCursor += len;

	return 0;
}

/*
 * pqPutnchar:
 *	write exactly len bytes to the current message
 */
int
pqPutnchar(const char *s, size_t len, PGconn *conn)
{
	if (pqPutMsgBytes(s, len, conn))
		return EOF;

	if (conn->Pfdebug)
	{
		fprintf(conn->Pfdebug, "To backend> ");
		fputnbytes(conn->Pfdebug, s, len);
		fprintf(conn->Pfdebug, "\n");
	}

	return 0;
}

/*
 * pqGetInt
 *	read a 2 or 4 byte integer and convert from network byte order
 *	to local byte order
 */
int
pqGetInt(int *result, size_t bytes, PGconn *conn)
{
	uint16		tmp2;
	uint32		tmp4;

	switch (bytes)
	{
		case 2:
			if (conn->inCursor + 2 > conn->inEnd)
				return EOF;
			memcpy(&tmp2, conn->inBuffer + conn->inCursor, 2);
			conn->inCursor += 2;
			*result = (int) ntohs(tmp2);
			break;
		case 4:
			if (conn->inCursor + 4 > conn->inEnd)
				return EOF;
			memcpy(&tmp4, conn->inBuffer + conn->inCursor, 4);
			conn->inCursor += 4;
			*result = (int) ntohl(tmp4);
			break;
		default:
			pqInternalNotice(&conn->noticeHooks,
							 "integer of size %lu not supported by pqGetInt",
							 (unsigned long) bytes);
			return EOF;
	}

	if (conn->Pfdebug)
		fprintf(conn->Pfdebug, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result);

	return 0;
}

int64
pqGetInt64(int64 *result, PGconn *conn)
{
    int64       tmp;
    uint32      h32;
    uint32      l32;

	if (conn->inCursor + 8 > conn->inEnd)
		return EOF;

    memcpy(&h32, conn->inBuffer + conn->inCursor, 4);
	conn->inCursor += 4;
	memcpy(&l32, conn->inBuffer + conn->inCursor, 4);
	conn->inCursor += 4;
    h32 = ntohl(h32);
    l32 = ntohl(l32);

#ifdef INT64_IS_BUSTED
    /* error out if incoming value is wider than 32 bits */
    tmp = l32;
    if ((tmp < 0) ? (h32 != -1) : (h32 != 0))
	{
		pqInternalNotice(&conn->noticeHooks,
						 "binary value is out of range for type bigint");
		return EOF;
	}
#else
    tmp = h32;
    tmp <<= 32;
    tmp |= l32;
#endif

	*result = tmp;
    return 0;
}

/*
 * pqPutInt
 * write an integer of 2 or 4 bytes, converting from host byte order
 * to network byte order.
 */
int
pqPutInt(int value, size_t bytes, PGconn *conn)
{
	uint16		tmp2;
	uint32		tmp4;

	switch (bytes)
	{
		case 2:
			tmp2 = htons((uint16) value);
			if (pqPutMsgBytes((const char *) &tmp2, 2, conn))
				return EOF;
			break;
		case 4:
			tmp4 = htonl((uint32) value);
			if (pqPutMsgBytes((const char *) &tmp4, 4, conn))
				return EOF;
			break;
		default:
			pqInternalNotice(&conn->noticeHooks,
							 "integer of size %lu not supported by pqPutInt",
							 (unsigned long) bytes);
			return EOF;
	}

	if (conn->Pfdebug)
		fprintf(conn->Pfdebug, "To backend (%lu#)> %d\n", (unsigned long) bytes, value);

	return 0;
}

/*
 * Make sure conn's output buffer can hold bytes_needed bytes (caller must
 * include already-stored data into the value!)
 *
 * Returns 0 on success, EOF if failed to enlarge buffer
 */
int
pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn)
{
	int	newsize = conn->outBufSize;
	char *newbuf;

	if (bytes_needed <= (size_t) newsize)
		return 0;

	/*
	 * If we need to enlarge the buffer, we first try to double it in size; if
	 * that doesn't work, enlarge in multiples of 8K.  This avoids thrashing
	 * the malloc pool by repeated small enlargements.
	 *
	 * Note: tests for newsize > 0 are to catch integer overflow.
	 */
	do
	{
		newsize *= 2;
	} while (newsize > 0 && bytes_needed > (size_t) newsize);

	if (newsize > 0 && bytes_needed <= (size_t) newsize)
	{
		newbuf = realloc(conn->outBuffer, newsize);
		if (newbuf)
		{
			/* realloc succeeded */
			conn->outBuffer = newbuf;
			conn->outBufSize = newsize;
			return 0;
		}
	}

	newsize = conn->outBufSize;
	do
	{
		newsize += 8192;
	} while (newsize > 0 && bytes_needed > (size_t) newsize);

	if (newsize > 0 && bytes_needed <= (size_t) newsize)
	{
		newbuf = realloc(conn->outBuffer, newsize);
		if (newbuf)
		{
			/* realloc succeeded */
			conn->outBuffer = newbuf;
			conn->outBufSize = newsize;
			return 0;
		}
	}

	/* realloc failed. Probably out of memory */
	printfPQExpBuffer(&conn->errorMessage,
					  "cannot allocate memory for output buffer\n");
	return EOF;
}

/*
 * Make sure conn's input buffer can hold bytes_needed bytes (caller must
 * include already-stored data into the value!)
 *
 * Returns 0 on success, EOF if failed to enlarge buffer
 */
int
pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
{
	int			newsize = conn->inBufSize;
	char	   *newbuf;

	if (bytes_needed <= (size_t) newsize)
		return 0;

	/*
	 * If we need to enlarge the buffer, we first try to double it in size; if
	 * that doesn't work, enlarge in multiples of 8K.  This avoids thrashing
	 * the malloc pool by repeated small enlargements.
	 *
	 * Note: tests for newsize > 0 are to catch integer overflow.
	 */
	do
	{
		newsize *= 2;
	} while (newsize > 0 && bytes_needed > (size_t) newsize);

	if (newsize > 0 && bytes_needed <= (size_t) newsize)
	{
		newbuf = realloc(conn->inBuffer, newsize);
		if (newbuf)
		{
			/* realloc succeeded */
			conn->inBuffer = newbuf;
			conn->inBufSize = newsize;
			return 0;
		}
	}

	newsize = conn->inBufSize;
	do
	{
		newsize += 8192;
	} while (newsize > 0 && bytes_needed > (size_t) newsize);

	if (newsize > 0 && bytes_needed <= (size_t) newsize)
	{
		newbuf = realloc(conn->inBuffer, newsize);
		if (newbuf)
		{
			/* realloc succeeded */
			conn->inBuffer = newbuf;
			conn->inBufSize = newsize;
			return 0;
		}
	}

	/* realloc failed. Probably out of memory */
	printfPQExpBuffer(&conn->errorMessage,
					  "cannot allocate memory for input buffer\n");
	return EOF;
}

/*
 * pqPutMsgStart: begin construction of a message to the server
 *
 * msg_type is the message type byte, or 0 for a message without type byte
 * (only startup messages have no type byte)
 *
 * force_len forces the message to have a length word; otherwise, we add
 * a length word if protocol 3.
 *
 * Returns 0 on success, EOF on error
 *
 * The idea here is that we construct the message in conn->outBuffer,
 * beginning just past any data already in outBuffer (ie, at
 * outBuffer+outCount).  We enlarge the buffer as needed to hold the message.
 * When the message is complete, we fill in the length word (if needed) and
 * then advance outCount past the message, making it eligible to send.
 *
 * The state variable conn->outMsgStart points to the incomplete message's
 * length word: it is either outCount or outCount+1 depending on whether
 * there is a type byte.  If we are sending a message without length word
 * (pre protocol 3.0 only), then outMsgStart is -1.  The state variable
 * conn->outMsgEnd is the end of the data collected so far.
 */
int
pqPutMsgStart(char msg_type, bool force_len, PGconn *conn)
{
	int			lenPos;
	int			endPos;

	/* allow room for message type byte */
	if (msg_type)
		endPos = conn->outCount + 1;
	else
		endPos = conn->outCount;

	/* do we want a length word? */
	if (force_len || PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
	{
		lenPos = endPos;
		/* allow room for message length */
		endPos += 4;
	}
	else
		lenPos = -1;

	/* make sure there is room for message header */
	if (pqCheckOutBufferSpace(endPos, conn))
		return EOF;
	/* okay, save the message type byte if any */
	if (msg_type)
		conn->outBuffer[conn->outCount] = msg_type;
	/* set up the message pointers */
	conn->outMsgStart = lenPos;
	conn->outMsgEnd = endPos;
	/* length word, if needed, will be filled in by pqPutMsgEnd */

	if (conn->Pfdebug)
		fprintf(conn->Pfdebug, "To backend> Msg %c\n",
				msg_type ? msg_type : ' ');

	return 0;
}

/*
 * pqPutMsgBytes: add bytes to a partially-constructed message
 *
 * Returns 0 on success, EOF on error
 */
static int
pqPutMsgBytes(const void *buf, size_t len, PGconn *conn)
{
	/* make sure there is room for it */
	if (pqCheckOutBufferSpace(conn->outMsgEnd + len, conn))
		return EOF;
	/* okay, save the data */
	memcpy(conn->outBuffer + conn->outMsgEnd, buf, len);
	conn->outMsgEnd += len;
	/* no Pfdebug call here, caller should do it */
	return 0;
}

/**
 * Same as pqPutMsgEnd except that data is NEVER flushed.
 */
void
pqPutMsgEndNoAutoFlush(PGconn *conn)
{
	if (conn->Pfdebug)
		fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n",
				conn->outMsgEnd - conn->outCount);

	/* Fill in length word if needed */
	if (conn->outMsgStart >= 0)
	{
		uint32		msgLen = conn->outMsgEnd - conn->outMsgStart;

		msgLen = htonl(msgLen);
		memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4);
	}

	/* Make message eligible to send */
	conn->outCount = conn->outMsgEnd;
}

/*
 * pqPutMsgEnd: finish constructing a message and possibly send it
 *
 * Returns 0 on success, EOF on error
 *
 * We don't actually send anything here unless we've accumulated at least
 * 8K worth of data (the typical size of a pipe buffer on Unix systems).
 * This avoids sending small partial packets.  The caller must use pqFlush
 * when it's important to flush all the data out to the server.
 */
int
pqPutMsgEnd(PGconn *conn)
{
	pqPutMsgEndNoAutoFlush(conn);

	if (conn->outCount >= 8192)
	{
		int			toSend = conn->outCount - (conn->outCount % 8192);

		if (pqSendSome(conn, toSend) < 0)
			return EOF;
		/* in nonblock mode, don't complain if unable to send it all */
	}

	return 0;
}

/* ----------
 * pqReadData: read more data, if any is available
 * Possible return values:
 *	 1: successfully loaded at least one more byte
 *	 0: no data is presently available, but no error detected
 *	-1: error detected (including EOF = connection closure);
 *		conn->errorMessage set
 * NOTE: callers must not assume that pointers or indexes into conn->inBuffer
 * remain valid across this call!
 * ----------
 */
int
pqReadData(PGconn *conn)
{
	int			someread = 0;
	int			nread;
	char		sebuf[256];

	if (conn->sock < 0)
	{
		printfPQExpBuffer(&conn->errorMessage,
						  libpq_gettext("connection not open\n"));
		return -1;
	}

	/* Left-justify any data in the buffer to make room */
	if (conn->inStart < conn->inEnd)
	{
		if (conn->inStart > 0)
		{
			memmove(conn->inBuffer, conn->inBuffer + conn->inStart,
					conn->inEnd - conn->inStart);
			conn->inEnd -= conn->inStart;
			conn->inCursor -= conn->inStart;
			conn->inStart = 0;
		}
	}
	else
	{
		/* buffer is logically empty, reset it */
		conn->inStart = conn->inCursor = conn->inEnd = 0;
	}

	/*
	 * If the buffer is fairly full, enlarge it. We need to be able to enlarge
	 * the buffer in case a single message exceeds the initial buffer size. We
	 * enlarge before filling the buffer entirely so as to avoid asking the
	 * kernel for a partial packet. The magic constant here should be large
	 * enough for a TCP packet or Unix pipe bufferload.  8K is the usual pipe
	 * buffer size, so...
	 */
	if (conn->inBufSize - conn->inEnd < 8192)
	{
		if (pqCheckInBufferSpace(conn->inEnd + (size_t) 8192, conn))
		{
			/*
			 * We don't insist that the enlarge worked, but we need some room
			 */
			if (conn->inBufSize - conn->inEnd < 100)
				return -1;		/* errorMessage already set */
		}
	}

	/* OK, try to read some data */
retry3:
	// Was pq_secure_read
	nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
						  conn->inBufSize - conn->inEnd, 0);
	if (nread < 0)
	{
		if (SOCK_ERRNO == EINTR)
			goto retry3;
		/* Some systems return EAGAIN/EWOULDBLOCK for no data */
#ifdef EAGAIN
		if (SOCK_ERRNO == EAGAIN)
			return someread;
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
		if (SOCK_ERRNO == EWOULDBLOCK)
			return someread;
#endif
		/* We might get ECONNRESET here if using TCP and backend died */
#ifdef ECONNRESET
		if (SOCK_ERRNO == ECONNRESET)
			goto definitelyFailed;
#endif
		printfPQExpBuffer(&conn->errorMessage,
				   libpq_gettext("could not receive data from server: %s\n"),
						  SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
		return -1;
	}
	if (nread > 0)
	{
		conn->inEnd += nread;

		/*
		 * Hack to deal with the fact that some kernels will only give us back
		 * 1 packet per recv() call, even if we asked for more and there is
		 * more available.	If it looks like we are reading a long message,
		 * loop back to recv() again immediately, until we run out of data or
		 * buffer space.  Without this, the block-and-restart behavior of
		 * libpq's higher levels leads to O(N^2) performance on long messages.
		 *
		 * Since we left-justified the data above, conn->inEnd gives the
		 * amount of data already read in the current message.	We consider
		 * the message "long" once we have acquired 32k ...
		 */
		if (conn->inEnd > 32768 &&
			(conn->inBufSize - conn->inEnd) >= 8192)
		{
			someread = 1;
			goto retry3;
		}
		return 1;
	}

	if (someread)
		return 1;				/* got a zero read after successful tries */

	/*
	 * A return value of 0 could mean just that no data is now available, or
	 * it could mean EOF --- that is, the server has closed the connection.
	 * Since we have the socket in nonblock mode, the only way to tell the
	 * difference is to see if select() is saying that the file is ready.
	 * Grumble.  Fortunately, we don't expect this path to be taken much,
	 * since in normal practice we should not be trying to read data unless
	 * the file selected for reading already.
	 *
	 */

	switch (pqReadReady(conn))
	{
		case 0:
			/* definitely no data available */
			return 0;
		case 1:
			/* ready for read */
			break;
		default:
			goto definitelyFailed;
	}

	/*
	 * Still not sure that it's EOF, because some data could have just
	 * arrived.
	 */
retry4:
	// was pq_secure_read
	nread = recv(conn->sock, conn->inBuffer + conn->inEnd,
						  conn->inBufSize - conn->inEnd, 0);
	if (nread < 0)
	{
		if (SOCK_ERRNO == EINTR)
			goto retry4;
		/* Some systems return EAGAIN/EWOULDBLOCK for no data */
#ifdef EAGAIN
		if (SOCK_ERRNO == EAGAIN)
			return 0;
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
		if (SOCK_ERRNO == EWOULDBLOCK)
			return 0;
#endif
		/* We might get ECONNRESET here if using TCP and backend died */
#ifdef ECONNRESET
		if (SOCK_ERRNO == ECONNRESET)
			goto definitelyFailed;
#endif
		printfPQExpBuffer(&conn->errorMessage,
				   libpq_gettext("could not receive data from server: %s\n"),
						  SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
		return -1;
	}
	if (nread > 0)
	{
		conn->inEnd += nread;
		return 1;
	}

	/*
	 * OK, we are getting a zero read even though select() says ready. This
	 * means the connection has been closed.  Cope.
	 */
definitelyFailed:
	printfPQExpBuffer(&conn->errorMessage,
					  libpq_gettext(
								"server closed the connection unexpectedly\n"
				   "\tThis probably means the server terminated abnormally\n"
							 "\tbefore or while processing the request.\n"));
	conn->status = CONNECTION_BAD;		/* No more connection to backend */
	//pqsecure_close(conn);
	closesocket(conn->sock);
	conn->sock = -1;

	return -1;
}

/*
 * pqSendSome: send data waiting in the output buffer.
 *
 * len is how much to try to send (typically equal to outCount, but may
 * be less).
 *
 * Return 0 on success, -1 on failure and 1 when not all data could be sent
 * because the socket would block and the connection is non-blocking.
 */
static int
pqSendSome(PGconn *conn, int len)
{
	char *ptr = conn->outBuffer;
	int	remaining = conn->outCount;
	int	result = 0;

	if (conn->sock < 0)
	{
		printfPQExpBuffer(&conn->errorMessage,
						  libpq_gettext("connection not open\n"));
		return -1;
	}

	/* while there's still data to send */
	while (len > 0)
	{
		int sent;
		char sebuf[256];

#ifndef WIN32
		sent = send(conn->sock, ptr, len, 0);
#else

		/*
		 * Windows can fail on large sends, per KB article Q201213. The
		 * failure-point appears to be different in different versions of
		 * Windows, but 64k should always be safe.
		 */
		sent = send(conn->sock, ptr, Min(len, 65536), 0);
#endif

		if (sent < 0)
		{
			/*
			 * Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble. If it's
			 * EPIPE or ECONNRESET, assume we've lost the backend connection
			 * permanently.
			 */
			switch (SOCK_ERRNO)
			{
#ifdef EAGAIN
				case EAGAIN:
					break;
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
				case EWOULDBLOCK:
					break;
#endif
				case EINTR:
					continue;

				case EPIPE:
#ifdef ECONNRESET
				case ECONNRESET:
#endif
					printfPQExpBuffer(&conn->errorMessage,
									  libpq_gettext(
								"server closed the connection unexpectedly\n"
					"\tThis probably means the server terminated abnormally\n"
							 "\tbefore or while processing the request.\n"));

					/*
					 * We used to close the socket here, but that's a bad idea
					 * since there might be unread data waiting (typically, a
					 * NOTICE message from the backend telling us it's
					 * committing hara-kiri...).  Leave the socket open until
					 * pqReadData finds no more data can be read.  But abandon
					 * attempt to send data.
					 */
					conn->outCount = 0;
					return -1;

				default:
					printfPQExpBuffer(&conn->errorMessage,
						libpq_gettext("could not send data to server: %s\n"),
							SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
					/* We don't assume it's a fatal error... */
					conn->outCount = 0;
					return -1;
			}
		}
		else
		{
			ptr += sent;
			len -= sent;
			remaining -= sent;
		}

		if (len > 0)
		{
			/*
			 * We didn't send it all, wait till we can send more.
			 *
			 * If the connection is in non-blocking mode we don't wait, but
			 * return 1 to indicate that data is still pending.
			 */
			if (pqIsnonblocking(conn))
			{
				result = 1;
				break;
			}

			/*
			 * There are scenarios in which we can't send data because the
			 * communications channel is full, but we cannot expect the server
			 * to clear the channel eventually because it's blocked trying to
			 * send data to us.  (This can happen when we are sending a large
			 * amount of COPY data, and the server has generated lots of
			 * NOTICE responses.)  To avoid a deadlock situation, we must be
			 * prepared to accept and buffer incoming data before we try
			 * again.  Furthermore, it is possible that such incoming data
			 * might not arrive until after we've gone to sleep.  Therefore,
			 * we wait for either read ready or write ready.
			 */
			if (pqReadData(conn) < 0)
			{
				result = -1;	/* error message already set up */
				break;
			}
			if (pqWait(TRUE, TRUE, conn))
			{
				result = -1;
				break;
			}
		}
	}

	/* shift the remaining contents of the buffer */
	if (remaining > 0)
	{
		if (conn->outBuffer_shared)
			conn->outBuffer = ptr;
		else
			memmove(conn->outBuffer, ptr, remaining);
	}
	conn->outCount = remaining;

	/* Once we finish with the external buffer, switch back to the original. */
	if (remaining == 0 && conn->outBuffer_shared)
	{
		conn->outBuffer_shared = false;
		conn->outBuffer = conn->outBufferSaved;
	}

	return result;
}

/*
 * pqFlush: send any data waiting in the output buffer
 *
 * Return 0 on success, -1 on failure and 1 when not all data could be sent
 * because the socket would block and the connection is non-blocking.
 */
int
pqFlush(PGconn *conn)
{
	if (conn->Pfdebug)
		fflush(conn->Pfdebug);

	if (conn->outCount > 0)
		return pqSendSome(conn, conn->outCount);

	return 0;
}

/*
 * pqFlushNonBlocking:
 *
 * wrapper for pqFlush, used by FileRep and dispatcher.
 * conn will be temporarily set to non-blocking mode,
 * so that if not all data could be sent on 1st attempt,
 * pqFlushNonBlocking will return 1 instead of waiting/retrying.
 *
 * Return 0 on success, -1 on failure and 1 when not all data could be sent
 */
int
pqFlushNonBlocking(PGconn *conn)
{
	bool old = conn->nonblocking;
	conn->nonblocking = TRUE;
	int ret = pqFlush(conn);
	conn->nonblocking = old;
	return ret;
}

/*
 * pqWait: wait until we can read or write the connection socket
 *
 *
 * We also stop waiting and return if the kernel flags an exception condition
 * on the socket.  The actual error condition will be detected and reported
 * when the caller tries to read or write the socket.
 */
int
pqWait(int forRead, int forWrite, PGconn *conn)
{
	return pqWaitTimed(forRead, forWrite, conn, (time_t) -1);
}

/*
 * pqWaitTimed: wait, but not past finish_time.
 *
 * If finish_time is exceeded then we return failure (EOF).  This is like
 * the response for a kernel exception because we don't want the caller
 * to try to read/write in that case.
 *
 * finish_time = ((time_t) -1) disables the wait limit.
 */
int
pqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time)
{
	int			result;

	result = pqSocketCheck(conn, forRead, forWrite, finish_time);

	if (result < 0)
		return EOF;				/* errorMessage is already set */

	if (result == 0)
	{
		printfPQExpBuffer(&conn->errorMessage,
						  libpq_gettext("timeout expired\n"));
		return EOF;
	}

	return 0;
}

/*
 * pgWaitTimeout: wait, but not past finish_time.
 * wrapper for pqSocketCheck.
 *
 * finish_time = ((time_t) -1) disables the wait limit.
 */
int
pqWaitTimeout(int forRead, int forWrite, PGconn *conn, time_t finish_time)
{
	int			result;

	result = pqSocketCheck(conn, forRead, forWrite, finish_time);

	if (result == 0)
	{
		printfPQExpBuffer(&conn->errorMessage,
						  libpq_gettext("timeout expired\n"));
	}

	return result;
}

/*
 * pqReadReady: is select() saying the file is ready to read?
 * Returns -1 on failure, 0 if not ready, 1 if ready.
 */
int
pqReadReady(PGconn *conn)
{
	return pqSocketCheck(conn, 1, 0, (time_t) 0);
}

/*
 * pqWriteReady: is select() saying the file is ready to write?
 * Returns -1 on failure, 0 if not ready, 1 if ready.
 */
int
pqWriteReady(PGconn *conn)
{
	return pqSocketCheck(conn, 0, 1, (time_t) 0);
}

/*
 * Checks a socket, using poll or select, for data to be read, written,
 * or both.  Returns >0 if one or more conditions are met, 0 if it timed
 * out, -1 if an error occurred.
 */
static int
pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time)
{
	int			result;

	if (!conn)
		return -1;
	if (conn->sock < 0)
	{
		printfPQExpBuffer(&conn->errorMessage,
						  libpq_gettext("socket not open\n"));
		return -1;
	}

	/* We will retry as long as we get EINTR */
	do
		result = pqSocketPoll(conn->sock, forRead, forWrite, end_time);
	while (result < 0 && SOCK_ERRNO == EINTR);

	if (result < 0)
	{
		char		sebuf[256];

		printfPQExpBuffer(&conn->errorMessage,
						  libpq_gettext("select() failed: %s\n"),
						  SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
	}

	return result;
}

/*
 * Check a file descriptor for read and/or write data, possibly waiting.
 * If neither forRead nor forWrite are set, immediately return a timeout
 * condition (without waiting).  Return >0 if condition is met, 0
 * if a timeout occurred, -1 if an error or interrupt occurred.
 *
 * Timeout is infinite if end_time is -1.  Timeout is immediate (no blocking)
 * if end_time is 0 (or indeed, any time before now).
 */
static int
pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time)
{
	/* We use poll(2) if available, otherwise select(2) */
#ifdef HAVE_POLL
	struct pollfd input_fd;
	int			timeout_ms;

	if (!forRead && !forWrite)
		return 0;

	input_fd.fd = sock;
	input_fd.events = POLLERR;
	input_fd.revents = 0;

	if (forRead)
		input_fd.events |= POLLIN;
	if (forWrite)
		input_fd.events |= POLLOUT;

	/* Compute appropriate timeout interval */
	if (end_time == ((time_t) -1))
		timeout_ms = -1;
	else
	{
		time_t		now = time(NULL);

		if (end_time > now)
			timeout_ms = (end_time - now) * 1000;
		else
			timeout_ms = 0;
	}

	return poll(&input_fd, 1, timeout_ms);
#else							/* !HAVE_POLL */

	mpp_fd_set		input_mask;
	mpp_fd_set		output_mask;
	mpp_fd_set		except_mask;
	struct timeval timeout;
	struct timeval *ptr_timeout;

	if (!forRead && !forWrite)
		return 0;

	MPP_FD_ZERO(&input_mask);
	MPP_FD_ZERO(&output_mask);
	MPP_FD_ZERO(&except_mask);
	if (forRead)
		MPP_FD_SET(sock, &input_mask);

	if (forWrite)
		MPP_FD_SET(sock, &output_mask);
	MPP_FD_SET(sock, &except_mask);

	/* Compute appropriate timeout interval */
	if (end_time == ((time_t) -1))
		ptr_timeout = NULL;
	else
	{
		time_t		now = time(NULL);

		if (end_time > now)
			timeout.tv_sec = end_time - now;
		else
			timeout.tv_sec = 0;
		timeout.tv_usec = 0;
		ptr_timeout = &timeout;
	}

	return select(sock + 1, (fd_set *)&input_mask, (fd_set *)&output_mask,
				  (fd_set *)&except_mask, ptr_timeout);
#endif   /* HAVE_POLL */
}

/*
 * A couple of "miscellaneous" multibyte related functions. They used
 * to be in fe-print.c but that file is doomed.
 */

/*
 * returns the byte length of the word beginning s, using the
 * specified encoding.
 */
int
PQmblen(const char *s, int encoding)
{
	return pg_encoding_mblen(encoding, s);
}

/*
 * returns the display length of the word beginning s, using the
 * specified encoding.
 */
int
PQdsplen(const char *s, int encoding)
{
	return pg_encoding_dsplen(encoding, s);
}

/*
 * Get encoding id from environment variable PGCLIENTENCODING.
 */
int
PQenv2encoding(void)
{
	char	   *str;
	int			encoding = PG_SQL_ASCII;

	str = getenv("PGCLIENTENCODING");
	if (str && *str != '\0')
	{
		encoding = pg_char_to_encoding(str);
		if (encoding < 0)
			encoding = PG_SQL_ASCII;
	}
	return encoding;
}

/*
 * This routine would only be called in main thread.
 */
struct HTAB *
PQprocessAoTupCounts(struct PartitionNode *parts, struct HTAB *ht,
					 void *aotupcounts, int naotupcounts)
{
	PQaoRelTupCount *ao = (PQaoRelTupCount *) aotupcounts;

	if (naotupcounts)
	{
		int	j;

		for (j = 0; j < naotupcounts; j++)
		{
			if (OidIsValid(ao->aorelid))
			{
				bool found;
				PQaoRelTupCount *entry;

				if (!ht)
				{
					HASHCTL	ctl;

					/*
					 * reasonable assumption?
					 */
					long num_buckets = list_length(all_partition_relids(parts));
					num_buckets /= num_partition_levels(parts);

					ctl.keysize = sizeof(Oid);
					ctl.entrysize = sizeof(*entry);
					ht = hash_create("AO hash map", num_buckets, &ctl, HASH_ELEM);
				}

				entry = hash_search(ht, &(ao->aorelid), HASH_ENTER, &found);

				if (found)
					entry->tupcount += ao->tupcount;
				else
					entry->tupcount = ao->tupcount;

			}
			ao++;
		}
	}

	return ht;
}


text:
package ro.mihaiblaga.imei;

import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollProxy;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.util.Log;
import org.appcelerator.titanium.util.TiConfig;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.view.TiCompositeLayout;
import org.appcelerator.titanium.view.TiCompositeLayout.LayoutArrangement;
import org.appcelerator.titanium.view.TiUIView;

import android.app.Activity;

// This proxy can be created by calling Imei.createExample({message: "hello world"})
@Kroll.proxy(creatableInModule=ImeiModule.class)
public class ExampleProxy extends TiViewProxy
{
	// Standard Debugging variables
	private static final String LCAT = "ExampleProxy";
	private static final boolean DBG = TiConfig.LOGD;

	private class ExampleView extends TiUIView
	{
		public ExampleView(TiViewProxy proxy) {
			super(proxy);
			LayoutArrangement arrangement = LayoutArrangement.DEFAULT;

			if (proxy.hasProperty(TiC.PROPERTY_LAYOUT)) {
				String layoutProperty = TiConvert.toString(proxy.getProperty(TiC.PROPERTY_LAYOUT));
				if (layoutProperty.equals(TiC.LAYOUT_HORIZONTAL)) {
					arrangement = LayoutArrangement.HORIZONTAL;
				} else if (layoutProperty.equals(TiC.LAYOUT_VERTICAL)) {
					arrangement = LayoutArrangement.VERTICAL;
				}
			}
			setNativeView(new TiCompositeLayout(proxy.getActivity(), arrangement));
		}

		@Override
		public void processProperties(KrollDict d)
		{
			super.processProperties(d);
		}
	}

	// Constructor
	public ExampleProxy()
	{
		super();
	}

	@Override
	public TiUIView createView(Activity activity)
	{
		TiUIView view = new ExampleView(this);
		view.getLayoutParams().autoFillsHeight = true;
		view.getLayoutParams().autoFillsWidth = true;
		return view;
	}

	// Handle creation options
	@Override
	public void handleCreationDict(KrollDict options)
	{
		super.handleCreationDict(options);

		if (options.containsKey("message")) {
			Log.d(LCAT, "example created with message: " + options.get("message"));
		}
	}

	// Methods
	@Kroll.method
	public void printMessage(String message)
	{
		Log.d(LCAT, "printing message: " + message);
	}

	@Kroll.getProperty @Kroll.method
	public String getMessage()
	{
        return "Hello World from my module";
	}

	@Kroll.setProperty @Kroll.method
	public void setMessage(String message)
	{
	    Log.d(LCAT, "Tried setting module message to: " + message);
	}
}

redpajama_set_name: RedPajamaGithub


text:
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Student Card Reader</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>

</resources>


text:
/** \file stlsoft/string/string_tokeniser.hpp
 *
 * \brief [C++ only] Definition of the stlsoft::string_tokeniser class
 *  template
 *   (\ref group__library__string "String" Library).
 */

#ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TOKENISER
#define STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TOKENISER

#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
# define STLSOFT_VER_STLSOFT_STRING_HPP_STRING_TOKENISER_MAJOR     5
# define STLSOFT_VER_STLSOFT_STRING_HPP_STRING_TOKENISER_MINOR     1
# define STLSOFT_VER_STLSOFT_STRING_HPP_STRING_TOKENISER_REVISION  8
# define STLSOFT_VER_STLSOFT_STRING_HPP_STRING_TOKENISER_EDIT      222
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */

/* /////////////////////////////////////////////////////////////////////////
 * Compatibility
 */

/*
[Incompatibilies-start]
STLSOFT_COMPILER_IS_DMC:  __DMC__<0x0839
STLSOFT_COMPILER_IS_MSVC: _MSC_VER<1200
STLSOFT_COMPILER_IS_WATCOM:
[Incompatibilies-end]
 */

/* /////////////////////////////////////////////////////////////////////////
 * Includes
 */

#ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
# include <stlsoft/stlsoft.h>
#endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */

#if defined(STLSOFT_COMPILER_IS_DMC) && \
    __DMC__ < 0x0839
# error stlsoft/string/string_tokeniser.hpp is not compatible with Digital Mars C/C++ 3.38 or earlier
#endif /* compiler */
#if defined(STLSOFT_COMPILER_IS_MSVC) && \
    _MSC_VER < 1100
# error stlsoft/string/string_tokeniser.hpp is not compatible with Visual C++ 5.0 or earlier
#endif /* compiler */

#ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
# include <stlsoft/util/std/iterator_helper.hpp>
#endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
#ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
# include <stlsoft/shims/access/string.hpp>
#endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
#ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
# include <stlsoft/collections/util/collections.hpp>
#endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */

#ifndef STLSOFT_INCL_ITERATOR
# define STLSOFT_INCL_ITERATOR
# include <iterator>                     // for std::distance()
#endif /* !STLSOFT_INCL_ITERATOR */

#ifdef STLSOFT_UNITTEST
# ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING
#  include <stlsoft/string/simple_string.hpp>
# endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING */
# ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_VIEW
#  include <stlsoft/string/string_view.hpp>
# endif /* STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_VIEW */
# include <string>
#endif /* STLSOFT_UNITTEST */

/* /////////////////////////////////////////////////////////////////////////
 * Compatibility
 */

#if defined(STLSOFT_STRING_TOKENISER_USE_DELIMITER_INDIRECTION) || \
    (   (   defined(STLSOFT_COMPILER_IS_MSVC) && \
            _MSC_VER < 1300) || \
        (   defined(STLSOFT_COMPILER_IS_INTEL) && \
            defined(WIN32) && \
            _MSC_VER < 1300))
# define STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION
#endif /* compiler */

/* /////////////////////////////////////////////////////////////////////////
 * Namespace
 */

#ifndef _STLSOFT_NO_NAMESPACE
namespace stlsoft
{
#endif /* _STLSOFT_NO_NAMESPACE */

/* /////////////////////////////////////////////////////////////////////////
 * Classes
 */

// string_tokeniser_ignore_blanks

/** \brief A tokenising policy for specifying whether blanks will be included or ignored (now deprecated; replaced by skip_blank_tokens)
 *
 * \ingroup group__library__string
 *
 * This policy determines whether a tokenisation will ignore blanks, or will present them as
 * (empty) entries in the sequence to the caller.
 *
 * \param B A boolean as to whether blanks should be ignored (\c true) or preserved (\c false)
 *
 * \deprecated Use skip_blank_tokens instead
 */
template <ss_bool_t B>
struct string_tokeniser_ignore_blanks
{
    enum { value = B };
};

/** \brief A tokenising policy for specifying whether blanks will be included or ignored
 *
 * \ingroup group__library__string
 *
 * This policy determines whether a tokenisation will ignore blanks, or will present them as
 * (empty) entries in the sequence to the caller.
 *
 * \param B A boolean as to whether blanks should be ignored (\c true) or preserved (\c false)
 *
 * \note This supercedes string_tokeniser_ignore_blanks
 */
template <ss_bool_t B>
struct skip_blank_tokens
{
    enum { value = B };
};

// string_tokeniser_type_traits
/** \brief A traits class for detecting features of the string type and the value type used to specialise string_tokeniser
 *
 * \ingroup group__library__string
 *
 * This traits class has three responsibilities. First, it defines a number of
 * member types that are used by the string_tokeniser and
 * string_tokeniser::iterator classes: value_type, const_iterator_type.
 *
 * Second, it provides a means by which the iterators of the string_tokeniser
 * specialisation's string type can be elicited, by defining the (static)
 * methods begin() and end().
 *
 * Third, it provides a means by which an instance of the string_tokeniser
 * specialisation's value type can be constructed from a pair of iterator of
 * the string type, by defining the (static) create() method.
 *
 * \param S The string tokeniser string type
 * \param V The string tokeniser value type
 */
template<   ss_typename_param_k S
        ,   ss_typename_param_k V
        >
struct string_tokeniser_type_traits
{
/// \name Member Types
/// @{
private:
    /// The string type
    typedef S                                       string_type;
    /// The tokeniser value type
    typedef V                                       tokeniser_value_type;

public:
    /// The value type
    typedef ss_typename_type_k S::value_type        value_type;
    /// The non-mutable (const) iterator type
    typedef ss_typename_type_k S::const_iterator    const_iterator_type;
/// @}

/// \name Operations
/// @{
public:
    /// Returns the start of the contained sequence of the given string
    static const_iterator_type begin(string_type const& s)
    {
        return s.begin();
    }

    /// Returns the end of the contained sequence of the given string
    static const_iterator_type end(string_type const& s)
    {
        return s.end();
    }

    /// Creates an instance of the string from the given range [f:t)
    static tokeniser_value_type create(const_iterator_type f, const_iterator_type t)
    {
        /* There's a bug in the Metrowerks 3.0 standard library string
         * implementation, such that constructing from a range leaves
         * a corrupted sequence due to an optimistic allocation
         * requirement calculation result being stored as the length
         */
#if defined(STLSOFT_COMPILER_IS_MWERKS) || \
    (   (   defined(STLSOFT_COMPILER_IS_INTEL) || \
            defined(STLSOFT_COMPILER_IS_MSVC) && \
        _MSC_VER == 1300))

        /// The size type
        typedef ss_typename_type_k S::size_type         size_type;

        return tokeniser_value_type(&*f, static_cast<size_type>(t - f));
#else /* ? compiler */
        return tokeniser_value_type(f, t);
#endif /* compiler */
    }
/// @}
};

// string_tokeniser_comparator
/** \brief A generic comparator, used to specialise string_tokeniser, that covers most string and delimiter types
 *
 * \ingroup group__library__string
 *
 * This the default tokeniser comparator, providing functionality for both
 * single-character and fixed string delimiters.
 *
 * \param D The delimiter type
 * \param S The string type
 * \param T The traits type
 */
template<   ss_typename_param_k D
        ,   ss_typename_param_k S
        ,   ss_typename_param_k T
        >
struct string_tokeniser_comparator
{
/// \name Member Types
/// @{
public:
    /// The delimiter type
    typedef D                                                   delimiter_type;
    /// The string type
    typedef S                                                   string_type;
    /// The traits type
    typedef T                                                   traits_type;
    /// The non-mutating (const) iterator type
    typedef ss_typename_type_k traits_type::const_iterator_type const_iterator;
private:
    typedef string_tokeniser_comparator<D, S, T>                class_type;
/// @}

/// \name Implementation
/// @{
private:
#if defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT) && \
    (   !defined(STLSOFT_COMPILER_IS_MSVC) || \
        _MSC_VER >= 1200)
    /// Evaluates whether the contents of the two sequences are equivalent to the given extent
    template<   ss_typename_param_k I1
            ,   ss_typename_param_k I2
            >
    static ss_bool_t is_equal_(I1 p1, I2 p2, ss_size_t n)
    {
        for(; n-- > 0; ++p1, ++p2)
        {
            if(*p1 != *p2)
            {
                return false;
            }
        }

        return true;
    }

    /// Evaluates whether the delimiter and the sequence are equivalent to the extent of the delimiter
    template<   ss_typename_param_k D1
            ,   ss_typename_param_k I
            >
    static ss_bool_t is_equal_(D1 const& delim, I &p2)
    {
        return class_type::is_equal_(delim.begin(), p2, delim.length());
    }

    /// Returns the length of the delimiter
    template <ss_typename_param_k D1>
    static ss_size_t get_length_(D1 const& delim)
    {
        return delim.length();
    }
#else /* ? STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
    /// Evaluates whether the contents of the two sequences are equivalent to the given extent
    static ss_bool_t is_equal_(string_type const& lhs, ss_typename_type_k string_type::value_type const* rhs)
    {
        { for(ss_size_t i = 0, n = lhs.length(); i < n; ++i)
        {
            if(lhs[i] != rhs[i])
            {
                return false;
            }
        }}

        return true;
    }

    /// Returns the length of the delimiter
    static ss_size_t get_length_(string_type const& s)
    {
        return s.length();
    }
#endif // STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT

    /// Evaluates whether the delimiter and the sequence are equivalent to the extent of the delimiter
    static ss_bool_t is_equal_(ss_char_a_t const delim, const_iterator &it)
    {
        return delim == *it;
    }
    /// Evaluates whether the delimiter and the sequence are equivalent to the extent of the delimiter
    static ss_bool_t is_equal_(ss_char_w_t const delim, const_iterator &it)
    {
        return delim == *it;
    }
    /// Returns the length of the delimiter
    static ss_size_t get_length_(ss_char_a_t const /* delim */)
    {
        return 1;
    }
    /// Returns the length of the delimiter
    static ss_size_t get_length_(ss_char_w_t const /* delim */)
    {
        return 1;
    }

#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
    static const_iterator advance_(const_iterator it, delimiter_type const& delim)
    {
        return it + get_length_(delim);
    }
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
/// @}

/// \name Operations
/// @{
public:
    /// Evaluates whether the delimiter and the sequence are not equivalent to the extent of the delimiter
    static ss_bool_t not_equal(delimiter_type const& delim, const_iterator &it)
    {
        return !is_equal_(delim, it);
    }

    /// Returns the length of the delimiter
    static ss_size_t length(delimiter_type const& delim)
    {
        return get_length_(delim);
    }

#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
    static ss_bool_t test_start_token_advance(const_iterator &it, const_iterator end, delimiter_type const& delim)
    {
        return is_equal_(delim, it) ? (it = advance_(it, delim), true) : false;
    }

    static ss_bool_t test_end_token_advance(const_iterator &it, const_iterator end, delimiter_type const& delim)
    {
        return is_equal_(delim, it) ? (it = advance_(it, delim), true) : false;
    }

    static const_iterator nonskip_move_to_start(const_iterator it, const_iterator end, delimiter_type const& delim)
    {
        return it;
    }

    static ss_bool_t test_end_token(const_iterator it, const_iterator end, delimiter_type const& delim)
    {
        return is_equal_(delim, it);
    }

    static const_iterator find_next_start(const_iterator it, const_iterator end, delimiter_type const& delim)
    {
        return advance_(it, delim);
    }
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
/// @}
};

/** \brief A class template that provides string tokenising behaviour
 *
 * \ingroup group__library__string
 *
 * This class takes a string, and a delimiter, and fashions a sequence from
 * the given string, with each element determined with respect to the
 * delimiter
 *
 * \param S The string type
 * \param D The delimiter type (can be a string type or a character type)
 * \param B The ignore-blanks type. Defaults to skip_blank_tokens<true>
 * \param V The value type (the string type that will be used for the values). Defaults to \c S
 * \param T The string type traits type. Defaults to string_tokeniser_type_traits<S, V>
 * \param P The tokeniser comparator type. Defaults to string_tokeniser_comparator<D, S, T>
 *
 * This class template provides tokenising services of a string (of type \c S)
 * with a delimiter (of type \c D). The four other template parameters, which are
 * defaulted, are used for tailoring the tokenising behaviour for special uses.
 *
 * The two typical supported tokenising scenarios are:
 *
 *  - tokenising a string with a character (e.g. '\\n')
 *  - tokenising a string with a string (e.g. "\\r\\n")
 *
 * More exotic scenarios are supported by customising the comparator and type-traits
 * parameters. (See stlsoft::charset_tokeniser.)
 *
 * 1. Tokenising a string with a character.
 *
 * This uses a specialisation whereby the first template parameter is a string type,
 * and the second parameter is a corresponding character type.
 *
 * The following code shows a specialisation using std::string and char, and
 * will output: abc,def,ghi,jkl,
 *
\code

stlsoft::string_tokeniser<std::string, char>  tokens(":abc::def:ghi:jkl::::::::::", ':');

std::copy(tokens.begin(), tokens.end(), std::ostream_iterator<std::string>(std::cout, ","));
\endcode
 *
 * The following code shows a specialisation using
 * stlsoft::basic_simple_string<wchar_t> and wchar_t, and
 * will output: abc-def-ghi-jkl-
 *
\code

typedef stlsoft::basic_simple_string<wchar_t>   string_t;
string_t                                        s(L"|abc||def|ghi|jkl||||||||||");
stlsoft::string_tokeniser<string_t, wchar_t>    tokens(s, L'|');

std::copy(tokens.begin(), tokens.end(), std::ostream_iterator<string_t, wchar_t>(std::wcout, L"-"));
\endcode
 *
 * Optionally, you can stipulate that the blanks be retained by specifying the third
 * template parameter as skip_blank_tokens<false>, as in the following, which will
 * output: ,abc,,def,ghi,jkl,,,,,,,,,,
 *
\code

stlsoft::string_tokeniser<  std::string
                        ,   char
                        ,   stlsoft::skip_blank_tokens<false>
                        >                tokens(":abc::def:ghi:jkl::::::::::", ':');

std::copy(tokens.begin(), tokens.end(), std::ostream_iterator<std::string>(std::cout, ","));
\endcode
 *
 * \note The tokeniser uses \ref group__concept__shim__string_access "String Access Shims" to elicit the
 * string from the given type, so any type that for which shims are defined can be passed to the
 * constructor, as in the following, which will output: abc;def;ghi;jkl;
 *
\code

#include <stlsoft/string/string_tokeniser.hpp>
#include <winstl/shims/access/string.hpp>

#include <iostream>
#include <iterator>

int main()
{
  HWND  hwndButton = ::CreateWindowEx(0, "BUTTON", "+abc++def+ghi+jkl++++++++++", 0, 0, 0, 0, 0, NULL, (HMENU)0, NULL, NULL);

  stlsoft::string_tokeniser<  std::string
                          ,   char
                          ,   stlsoft::skip_blank_tokens<true>
                          >                tokens(hwndButton, '+');
  std::copy(tokens.begin(), tokens.end(), std::ostream_iterator<std::string>(std::cout, ";"));
  return 0;
}
\endcode
 *
 * 2. Tokenising a string with a string.
 *
 * This uses a specialisation whereby the first template parameter is a string type,
 * and the second parameter is a corresponding string type.
 *
 * The following code shows a specialisation using std::string and std::string, and
 * will output: abc,def,ghi,jkl,
 *
\code

stlsoft::string_tokeniser<std::string, std::string>  tokens("\r\nabc\r\n\r\ndef\r\nghi\r\njkl\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n", "\r\n");

std::copy(tokens.begin(), tokens.end(), std::ostream_iterator<std::string>(std::cout, ","));
\endcode
 */
template<   ss_typename_param_k S
        ,   ss_typename_param_k D
#ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT
        ,   ss_typename_param_k B = skip_blank_tokens<true>
        ,   ss_typename_param_k V = S
        ,   ss_typename_param_k T = string_tokeniser_type_traits<S, V>
        ,   ss_typename_param_k P = string_tokeniser_comparator<D, S, T>
#else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
        ,   ss_typename_param_k B
        ,   ss_typename_param_k V
        ,   ss_typename_param_k T
        ,   ss_typename_param_k P
#endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
        >
class string_tokeniser
    : public stl_collection_tag
{
/// \name Member Types
/// @{
public:
    /// The current parameterisation of the type
    typedef string_tokeniser<S, D, B, V, T, P>              class_type;
    /// This tokeniser parameterisation
    typedef string_tokeniser<S, D, B, V, T, P>              tokeniser_type;
    /// The sequence string type
    typedef S                                               string_type;
    /// The delimiter type
    typedef D                                               delimiter_type;
    /// The blanks policy type
    typedef B                                               blanks_policy_type;
#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
    typedef B                                               ignore_blanks_type;
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
    /// The value type
    typedef V                                               value_type;
    /// The traits type
    typedef T                                               traits_type;
    /// The tokeniser comparator type
    typedef P                                               comparator_type;
    /// The character type
    typedef ss_typename_type_k traits_type::value_type      char_type;
    /// The size type
    ///
    /// \note This no longer relies on a size_type member type of the traits type (T). It is defined
    /// as size_t
    typedef ss_size_t                                       size_type;
    /// The difference type
    ///
    /// \note This no longer relies on a difference_type member type of the traits type (T). It is defined
    /// as ptrdiff_t
    typedef ss_ptrdiff_t                                    difference_type;
    /// The non-mutating (const) reference type
    typedef const value_type                                const_reference;
    /// The non-mutating (const) iterator type
    class                                                   const_iterator;
/// @}

/// \name Construction
/// @{
public:
    /// Tokenise the given C-string with the given delimiter
    ///
    /// \param psz Pointer to C-string whose contents will be tokenised
    /// \param delim The delimiter to perform the tokenisation
    ///
    /// \note The tokeniser class takes a copy of \c psz. It does not alter the contents of \c psz
    string_tokeniser(char_type const* psz, delimiter_type const& delim)
        : m_str(psz)
        , m_delimiter(delim)
    {
        STLSOFT_MESSAGE_ASSERT("Delimiter of zero-length", 0 != comparator_type::length(m_delimiter));

        STLSOFT_ASSERT(is_valid());
    }

// Define the string_type overload if there member template ctors are not supported, or
// they are correctly discriminated
#if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
    defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED)
    /// Tokenise the given string with the given delimiter
    ///
    /// \param str The string whose contents will be tokenised
    /// \param delim The delimiter to perform the tokenisation
    ///
    /// \note The tokeniser class takes a copy of \c str. It does not alter the contents of \c str
    string_tokeniser(string_type const& str, delimiter_type const& delim)
        : m_str(str)
        , m_delimiter(delim)
    {
        STLSOFT_MESSAGE_ASSERT("Delimiter of zero-length", 0 != comparator_type::length(m_delimiter));

        STLSOFT_ASSERT(is_valid());
    }
#endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */

// Define the template overload if member template ctors are supported
#if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT)
    /// Tokenise the given string with the given delimiter
    ///
    /// \param str The string whose contents will be tokenised
    /// \param delim The delimiter to perform the tokenisation
    ///
    /// \note The tokeniser class takes a copy of \c str. It does not alter the contents of \c str
    template <ss_typename_param_k S1>
    string_tokeniser(S1 const& str, delimiter_type const& delim)
        : m_str(c_str_data(str), c_str_len(str))
        , m_delimiter(delim)
    {
        STLSOFT_MESSAGE_ASSERT("Delimiter of zero-length", 0 != comparator_type::length(m_delimiter));

        STLSOFT_ASSERT(is_valid());
    }
#endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */

    /// Tokenise the specified length of the given string with the given delimiter
    ///
    /// \param psz Pointer to C-string whose contents will be tokenised
    /// \param cch The number of characters in \c psz to use
    /// \param delim The delimiter to perform the tokenisation
    ///
    /// \note The tokeniser class takes a copy of \c psz. It does not alter the contents of \c psz
    string_tokeniser(char_type const* psz, size_type cch, delimiter_type const& delim)
        : m_str(psz, cch)
        , m_delimiter(delim)
    {
        STLSOFT_MESSAGE_ASSERT("Delimiter of zero-length", 0 != comparator_type::length(m_delimiter));

        STLSOFT_ASSERT(is_valid());
    }

#if !defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT) || \
    defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED)
    /// \brief Tokenise the given range with the given delimiter
    ///
    /// \param from The start of the asymmetric range to tokenise
    /// \param to The start of the asymmetric range to tokenise
    /// \param delim The delimiter to use
    string_tokeniser(char_type const* from, char_type const* to, delimiter_type const& delim)
        : m_str(from, to)
        , m_delimiter(delim)
    {
        STLSOFT_MESSAGE_ASSERT("Delimiter of zero-length", 0 != comparator_type::length(m_delimiter));

        STLSOFT_ASSERT(is_valid());
    }
#endif /* !STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_CTOR_OVERLOAD_DISCRIMINATED */

#if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT)
    /// Tokenise the given range with the given delimiter
    ///
    /// \param from The start of the asymmetric range to tokenise
    /// \param to The start of the asymmetric range to tokenise
    /// \param delim The delimiter to use
    template <ss_typename_param_k I>
    string_tokeniser(I from, I to, delimiter_type const& delim)
        : m_str(from, to)
        , m_delimiter(delim)
    {
        STLSOFT_MESSAGE_ASSERT("Delimiter of zero-length", 0 != comparator_type::length(m_delimiter));

        STLSOFT_ASSERT(is_valid());
    }
#endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
/// @}

/// \name Iteration
/// @{
public:
    /// Iterator for string_tokeniser, supporting the Forward Iterator concept
    class const_iterator
        : public iterator_base< stlsoft_ns_qual_std(forward_iterator_tag)
                            ,   value_type
                            ,   ss_ptrdiff_t
                            ,   void
                            ,   value_type
                            >
    {
    /// \name Member Types
    /// @{
    public:
        /// The type
        typedef const_iterator                                      class_type;
#if (   defined(STLSOFT_COMPILER_IS_DMC) && \
        __DMC__ <= 0x0843) || \
    defined(STLSOFT_COMPILER_IS_MSVC)
        /// The delimiter type
        typedef delimiter_type                                      delimiter_type;
        /// The value type
        typedef value_type                                          value_type;
        /// The traits type
        typedef traits_type                                         traits_type;
#else /* ? compiler */
        /// The delimiter type
        typedef ss_typename_type_k tokeniser_type::delimiter_type   delimiter_type;
        /// The value type
        typedef ss_typename_type_k tokeniser_type::value_type       value_type;
        /// The traits type
        typedef ss_typename_type_k tokeniser_type::traits_type      traits_type;
#endif /* compiler */
        typedef value_type                                          effective_const_reference;
    private:
        typedef ss_typename_type_k traits_type::const_iterator_type underlying_iterator_type;
# if defined(STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION)
        typedef delimiter_type const*                               delimiter_ref_type;
# else /* ? STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION */
        typedef delimiter_type                                      delimiter_ref_type;
# endif /* STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION */
    /// @}

    /// \name Construction
    /// @{
    private:
        friend class    string_tokeniser<S, D, B, V, T, P>;

        /// Conversion constructor
        const_iterator(underlying_iterator_type first, underlying_iterator_type last, delimiter_type const& delimiter)
            : m_find0(first)
            , m_find1(first)
            , m_next(first)
            , m_end(last)
# if defined(STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION)
            , m_delimiter(&delimiter)
# else /* ? STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION */
            , m_delimiter(delimiter)
# endif /* STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION */
            , m_cchDelimiter(comparator_type::length(delimiter))
        {
            if(m_end != m_find0)
            {
                increment_();
            }
        }
    public:
        /// Default constructor
        const_iterator()
            : m_find0(NULL)
            , m_find1(NULL)
            , m_next(NULL)
            , m_end(NULL)
            , m_delimiter(delimiter_ref_type())
            , m_cchDelimiter(0)
        {}

        /// Copy constructor
        ///
        /// \param rhs The iterator whose current search position will be copied
        const_iterator(class_type const& rhs)
            : m_find0(rhs.m_find0)
            , m_find1(rhs.m_find1)
            , m_next(rhs.m_next)
            , m_end(rhs.m_end)
            , m_delimiter(rhs.m_delimiter)
            , m_cchDelimiter(comparator_type::length(get_delim_ref_(rhs.m_delimiter)))
        {}

        /// Copy-assignment operator
        ///
        /// \param rhs The iterator whose current search position will be copied
        class_type const& operator =(class_type const& rhs)
        {
            m_find0         =   rhs.m_find0;
            m_find1         =   rhs.m_find1;
            m_next          =   rhs.m_next;
            m_end           =   rhs.m_end;
            m_delimiter     =   rhs.m_delimiter;
            m_cchDelimiter  =   rhs.m_cchDelimiter;

            return *this;
        }
    /// @}

    /// \name Forward Iterator Methods
    /// @{
    public:
        /// Dereference operator
        //
        // This has to be V, rather than value_type, because Visual C++ thinks that S is the value_type!!
        const V operator *() const
        {
            return traits_type::create(m_find0, m_find1);
        }

        /// Pre-increment operator
        class_type& operator ++()
        {
            increment_();

            return *this;
        }

        /// Post-increment operator
        const class_type operator ++(int)
        {
            class_type  ret(*this);

            operator ++();

            return ret;
        }

        /// Evaluates whether \c this and \c rhs are equivalent
        ss_bool_t equal(class_type const& rhs) const
        {
            STLSOFT_MESSAGE_ASSERT("Comparing iterators from different tokenisers", m_end == rhs.m_end);

            return m_find0 == rhs.m_find0;
        }

        /// Evaluates whether \c this and \c rhs are equivalent
        ss_bool_t operator == (class_type const& rhs) const
        {
            return equal(rhs);
        }

        /// Evaluates whether \c this and \c rhs are not equivalent
        ss_bool_t operator != (class_type const& rhs) const
        {
            return !equal(rhs);
        }
    /// @}

    /// \name Implementation
    /// @{
    private:
        static delimiter_type const& get_delim_ref_(delimiter_ref_type const& delim)
        {
# if defined(STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION)
            return *delim;
# else /* ? STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION */
            return delim;
# endif /* STLSOFT_STRING_TOKENISER_CF_REQUIRE_DELIMITER_INDIRECTION */
        }

        void increment_()
        {
            STLSOFT_MESSAGE_ASSERT("Attempting to increment an invalid iterator", m_find0 != m_end);

            // This is a two-phase algorithm:
            //
            // 1. If skipping blanks, then do that. Otherwise, locate the the start-of-item
            //     iterator (m_find0) to the previously identified start of the next item (m_next)
            // 2. Starting from m_find0, determine the end-of-item (m_find1)

// TODO: Make this into a overload-selector, to avoid the "conditional expression is constant" warning
            if(blanks_policy_type::value)
            {
                // 1. Skip blanks until at start of next item
                for(m_find0 = m_next; m_find0 != m_end; )
                {
                    if(comparator_type::not_equal(get_delim_ref_(m_delimiter), m_find0))
                    {
                        break;
                    }
                    else
                    {
                        m_find0 +=  static_cast<ss_ptrdiff_t>(m_cchDelimiter);
                    }
                }
            }
            else
            {
                m_find0 = m_next;
            }

            // 2. Determine the end-of-item (m_find1), starting from m_find0
            for(m_find1 = m_find0; ; )
            {
                if(m_find1 == m_end)
                {
                    // End of sequence. Item will be [m_find0, m_end (== m_find1))
                    m_next = m_find1;
                    break;
                }
                else if(comparator_type::not_equal(get_delim_ref_(m_delimiter), m_find1))
                {
                    // current item does not hold a delimiter, so advance one position
                    ++m_find1;
                }
                else
                {
                    // Determine the start of the next potential element, ready
                    // for the next call of increment_()
                    m_next = m_find1 + static_cast<ss_ptrdiff_t>(m_cchDelimiter);

                    break;
                }
            }
        }
    /// @}

    /// \name Members
    /// @{
    private:
        underlying_iterator_type    m_find0;        // the start of the current item
        underlying_iterator_type    m_find1;        // the end of the current item
        underlying_iterator_type    m_next;         // the start of the next valid (non-null) item
        underlying_iterator_type    m_end;          // end point of controlled sequence
        delimiter_ref_type          m_delimiter;    // The delimiter
        ss_size_t                   m_cchDelimiter;
    /// @}
    };

    /// Begins the iteration
    ///
    /// \return An iterator representing the start of the sequence
    const_iterator begin() const
    {
        STLSOFT_ASSERT(is_valid());

        return const_iterator(traits_type::begin(m_str), traits_type::end(m_str), m_delimiter);
    }
    /// Ends the iteration
    ///
    /// \return An iterator representing the end of the sequence
    const_iterator end() const
    {
        STLSOFT_ASSERT(is_valid());

        return const_iterator(traits_type::end(m_str), traits_type::end(m_str), m_delimiter);
    }
/// @}

/// \name Attributes
/// @{
public:
    /// Indicates whether the search sequence is empty
    ss_bool_t   empty() const
    {
        STLSOFT_ASSERT(is_valid());

        return begin() == end();
    }
/// @}

/// \name Invariant
/// @{
private:
    ss_bool_t is_valid() const
    {
        return true;
    }
/// @}

/// \name Members
/// @{
private:
    string_type const       m_str;
    delimiter_type const    m_delimiter;
/// @}

/// \name Not to be implemented
/// @{
private:
    class_type const& operator =(class_type const&);
/// @}
};

/* /////////////////////////////////////////////////////////////////////////
 * Operators
 */

#if 0
/** \brief Evaluates whether \c this and \c rhs are equivalent
 *
 * \ingroup group__library__string
 */
template<   ss_typename_param_k S
        ,   ss_typename_param_k D
        ,   ss_typename_param_k B
        ,   ss_typename_param_k V
        ,   ss_typename_param_k T
        ,   ss_typename_param_k P
        >
inline ss_bool_t operator ==(   ss_typename_type_k string_tokeniser<S, D, B, V, T, P>::const_iterator const& lhs
                            ,   ss_typename_type_k string_tokeniser<S, D, B, V, T, P>::const_iterator const& rhs)
{
    return lhs.equal(rhs);
}

/** \brief Evaluates whether \c this and \c rhs are not equivalent
 *
 * \ingroup group__library__string
 */
template<   ss_typename_param_k S
        ,   ss_typename_param_k D
        ,   ss_typename_param_k B
        ,   ss_typename_param_k V
        ,   ss_typename_param_k T
        ,   ss_typename_param_k P
        >
inline ss_bool_t operator !=(   ss_typename_type_k string_tokeniser<S, D, B, V, T, P>::const_iterator const& lhs
                            ,   ss_typename_type_k string_tokeniser<S, D, B, V, T, P>::const_iterator const& rhs)
{
    return !lhs.equal(rhs);
}
#endif /* 0 */

/* /////////////////////////////////////////////////////////////////////////
 * Unit-testing
 */

#ifdef STLSOFT_UNITTEST
# include "./unittest/string_tokeniser_unittest_.h"
#endif /* STLSOFT_UNITTEST */

/* ////////////////////////////////////////////////////////////////////// */

#if defined(STLSOFT_COMPILER_IS_DMC) && \
    !defined(_STLPORT_VERSION)
template<   ss_typename_param_k S
        ,   ss_typename_param_k D
        ,   ss_typename_param_k B
        ,   ss_typename_param_k V
        ,   ss_typename_param_k T
        ,   ss_typename_param_k P
        >
inline forward_iterator_tag iterator_category(string_tokeniser<S, D, B, V, T, P>::const_iterator const&)
{
    return forward_iterator_tag();
}

template<   ss_typename_param_k S
        ,   ss_typename_param_k D
        ,   ss_typename_param_k B
        ,   ss_typename_param_k V
        ,   ss_typename_param_k T
        ,   ss_typename_param_k P
        >
inline ss_ptrdiff_t* distance_type(string_tokeniser<S, D, B, V, T, P>::const_iterator const&)
{
    return static_cast<ss_ptrdiff_t*>(0);
}
#endif /* compiler */

/* ////////////////////////////////////////////////////////////////////// */

#ifndef _STLSOFT_NO_NAMESPACE
} // namespace stlsoft
#endif /* _STLSOFT_NO_NAMESPACE */

/* ////////////////////////////////////////////////////////////////////// */

#endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TOKENISER */

/* ///////////////////////////// end of file //////////////////////////// */


text:
/* parameter untuk menjalankan fungsi openContent ini adalah
	     1. Element trigger (link) yang akan membuka content apabila di click
	     2. Id dari content yang akan ditampilkan
	  */
	 /* Update 08 Maret 2009
		 -> Slideshow diberikan animasi otomatis berpindah-pindah content
	 */
	 // siapkan variable timer yang akan menyimpan fungsi animasi
	 var timer = null;
	 function bukaContent(trigger,divID){
	 	// semua link pada div dengan id='divTrigger' akan di setarakan style-nya menjadi style normal
	 	$('#divTrigger a').each(
	 		function(){
			 	$(this).css({'background-color':'white','color':'white'});
			}
	 	);
	 	// semua div di dalam element dengan id='divContent' disembunyikan
	 	$('#divContent div').hide();

	 	// div yang akan ditampilkan diberi efek fadeIn (built-in dari JQuery) ketika ditampilkan
	 	$('#'+divID).fadeIn('slow');

	 	// link menjadi trigger diberi style berbeda dengan link lainnya agar dapat diketahui content nomor berapa yang sedang aktif
	 	$(trigger).css({'background-color':'#white','color':'white'});

		// Update 08 Maret 2009
		// timer di set
		if(timer != null) clearTimeout(timer);
		timer = setTimeout(
		  function(){
			/* Cek terlebih dahulu apakah link yang sedang di-click saat ini ada link lagi setelah itu
			   apabila tidak ada link lagi setelah element yang sedang di-click maka pilih element link pertama
			   dengan selector ':first' dari jquery. Setelah sudah ditentukan link, maka lakukan event click
			   pada link tersebut. Setiap link yang di click akan menjalankan fungsi ini sehingga terjadi animasi
			   perpindahan content slideshow.
			*/
			var nextAnchor = ($(trigger).next('a').text() == '') ? $('#divTrigger a:first') : $(trigger).next('a');
			nextAnchor.click();
		  }, 3000 // 3 detik waktu perpindahan antar content di headline
		);
	 }


text:
#include "PullRequest.h"
#include "UtilAll.h"

namespace rmq
{

PullRequest::~PullRequest()
{

}

std::string PullRequest::getConsumerGroup()
{
    return m_consumerGroup;
}

void PullRequest::setConsumerGroup(const std::string& consumerGroup)
{
    m_consumerGroup = consumerGroup;
}

MessageQueue& PullRequest::getMessageQueue()
{
    return m_messageQueue;
}

void PullRequest::setMessageQueue(const MessageQueue& messageQueue)
{
    m_messageQueue = messageQueue;
}

long long PullRequest::getNextOffset()
{
    return m_nextOffset;
}

void PullRequest::setNextOffset(long long nextOffset)
{
    m_nextOffset = nextOffset;
}

int PullRequest::hashCode()
{
    /*
    final int prime = 31;
    int result = 1;
    result = prime * result + ((consumerGroup == null) ? 0 : consumerGroup.hashCode());
    result = prime * result + ((messageQueue == null) ? 0 : messageQueue.hashCode());
    return result;
    */
    std::stringstream ss;
    ss  << m_consumerGroup
        << m_messageQueue.hashCode();
    return UtilAll::hashCode(ss.str());
}

std::string PullRequest::toString() const
{
    std::stringstream ss;
    ss << "{consumerGroup=" << m_consumerGroup
       << ",messageQueue=" << m_messageQueue.toString()
       << ",nextOffset=" << m_nextOffset << "}";
    return ss.str();
}

bool PullRequest::operator==(const PullRequest& other)
{
    if (m_consumerGroup != other.m_consumerGroup)
    {
        return false;
    }

    if (!(m_messageQueue == other.m_messageQueue))
    {
        return false;
    }

    return true;
}

ProcessQueue* PullRequest::getProcessQueue()
{
    return m_pProcessQueue;
}

void PullRequest::setProcessQueue(ProcessQueue* pProcessQueue)
{
    m_pProcessQueue = pProcessQueue;
}

}


text:
<?php

namespace Gajdaw\BDDTutorial\AppBundle\DataFixtures\ORM;

use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Yaml\Yaml;
use AppBundle\Entity\Wydzial;

class LoadWydzial implements FixtureInterface
{
    /**
     * {@inheritDoc}
     */
    public function load(ObjectManager $manager)
    {

        $filename = __DIR__ . '/../../data/Wydzial.yml';
        $yml = Yaml::parse(file_get_contents($filename));
        foreach ($yml as $item) {
            $wydzial = new Wydzial();
            $wydzial->setNazwa($item['nazwa']);
            $manager->persist($wydzial);
        }

        $manager->flush();
    }
}


text:
#include "DrawingProjection.h"
#include "MC2Point.h"
#include "MC2Coordinate.h"
#include "Packet.h"
#include "GfxConstants.h"
#include "CoordinateTransformer.h"
#include "MapUtility.h"

// Drawing projection
DrawingProjection::DrawingProjection( DrawingProjection::projection_t type,
                                      const MC2Point& size )
      : m_pixelBox( MC2Point(0,0), size ),
        m_projectionType(type)

{
}

DrawingProjection*
DrawingProjection::create( const Packet* p, int& pos )
{
   DrawingProjection* result = NULL;

   DrawingProjection::projection_t type =
      (DrawingProjection::projection_t) p->incReadLong( pos );
   switch( type ) {
      case DrawingProjection::cosLatProjection : {
         MC2BoundingBox bbox;
         p->incReadBBox( pos, bbox );
         int32 height = p->incReadLong( pos );
         int32 width = p->incReadLong( pos );
         int16 rotationAngle = p->incReadShort( pos );

         result = new CosLatProjection( bbox,
                                        height,
                                        width,
                                        rotationAngle );
         result->init();
      }
         break;
      case DrawingProjection::braunProjection : {
         MC2BoundingBox bbox;
         p->incReadBBox( pos, bbox );
         int32 latIndex = p->incReadLong( pos );
         int32 lonIndex = p->incReadLong( pos );
         int32 zoomLevel = p->incReadLong( pos );
         int32 nbrPixels = p->incReadLong( pos );

         result = new BraunProjection( latIndex,
                                       lonIndex,
                                       zoomLevel,
                                       nbrPixels );
         result->init();
      }
         break;
      case DrawingProjection::mercatorProjection : {
         MC2BoundingBox bbox;
         p->incReadBBox( pos, bbox );
         int32 latIndex = p->incReadLong( pos );
         int32 lonIndex = p->incReadLong( pos );
         int32 zoomLevel = p->incReadLong( pos );
         int32 nbrPixels = p->incReadLong( pos );

         result = new MercatorProjection( latIndex,
                                          lonIndex,
                                          zoomLevel,
                                          nbrPixels );
         result->init();
      }
         break;
      default:
         mc2log << warn << "DrawingProjection::create() "
                << "Unknown projection type." << endl;
         exit(1);

         break;
   }
   return result;
}

POINT
DrawingProjection::getPointFromCoordinate( const MC2Coordinate& coord ) const
{
   MC2Point p = getPoint( coord );
   POINT returnPoint = { p.getX(), p.getY()};

   return returnPoint;
}

MC2Coordinate
DrawingProjection::getCoordinateFromPoint( const POINT& point ) const
{
   MC2Point p = MC2Point( point.x, point.y );
   return getCoordinate( p );
}

DrawingProjection::projection_t
DrawingProjection::getProjectionType() const
{
   return m_projectionType;
}

StringTableUTF8::stringCode
DrawingProjection::getStatus() const
{
   return m_status;
}

// CosLat projection
CosLatProjection::CosLatProjection( const MC2BoundingBox& bbox,
                                    int32 height,
                                    int32 width,
                                    int16 rotationAngle )
      : DrawingProjection( DrawingProjection::cosLatProjection,
                           MC2Point( width, height ) )
{
   m_bbox.setMaxLat( bbox.getMaxLat() );
   m_bbox.setMaxLon( bbox.getMaxLon() );
   m_bbox.setMinLat( bbox.getMinLat() );
   m_bbox.setMinLon( bbox.getMinLon() );
   m_height = height;
   m_width = width;
   m_rotationAngle = rotationAngle;
   m_bbox.updateCosLat();
   init();
}

void
CosLatProjection::init()
{
   m_xscale = float64(m_width - 1) / m_bbox.getLonDiff();
   m_yscale = float64(m_height - 1) / m_bbox.getHeight();

   // Make sure that the image will not have strange proportions.
   float64 factor = float64(m_bbox.getHeight()) / m_bbox.getWidth()
      * (m_width - 1) / (m_height - 1);

   if (factor < 1) {
      //  Compensate for that the image is wider than it is high
      m_yscale *= factor;
   } else {
      // Compensate for that the image is higher than it is wide
      m_xscale /= factor;
   }
   m_status = StringTableUTF8::OK;
}

void
CosLatProjection::save( Packet* p, int& pos ) const
{
   // Write the projection type
   p->incWriteLong( pos, DrawingProjection::cosLatProjection );

   // Write the bounding box
   p->incWriteBBox( pos, m_bbox );

   // Write the height and width
   p->incWriteLong( pos, m_height );
   p->incWriteLong( pos, m_width );

   // Write the map rotation
   p->incWriteShort( pos, m_rotationAngle );
}

MC2Point
CosLatProjection::getPoint( const MC2Coordinate& coord ) const
{
   int32 unrotated_xcoord, unrotated_ycoord;
   // xcoord
   unrotated_xcoord =
      int32(rint((coord.lon - m_bbox.getMinLon()) * m_xscale));
   if (unrotated_xcoord > (m_width*2))
      unrotated_xcoord = m_width*2;
   else if (unrotated_xcoord < (-m_width*2))
      unrotated_xcoord = -m_width*2 ;
   // ycoord
   unrotated_ycoord = int32(m_height) - 1 -
      int32(rint((coord.lat - m_bbox.getMinLat()) * m_yscale));
   if (unrotated_ycoord > (m_height*2))
      unrotated_ycoord = m_height*2;
   else if (unrotated_ycoord < (-m_height*2))
      unrotated_ycoord = -m_height*2;

   int32 xcoord, ycoord;
   if( m_rotationAngle == 0 ) {
      if ( coord.lat == m_bbox.getMinLat() ) {
         ycoord = m_height;
      } else {
         ycoord = unrotated_ycoord;
      }
      if ( coord.lon == m_bbox.getMaxLon() ) {
         xcoord = m_width;
      } else {
         xcoord = unrotated_xcoord;
      }

   } else {
      float64 angleRad = (m_rotationAngle / 180.0) * M_PI;

      int32 halfImageWidth = m_width / 2;
      int32 halfImageHeight = m_height / 2;

      // Translate origo to the center.
      int32 translatedImageX = unrotated_xcoord - halfImageWidth;
      int32 translatedImageY = unrotated_ycoord - halfImageHeight;

      float64 sinAngle = sin(angleRad);
      float64 cosAngle = cos(angleRad);

      // Rotate around origo. (clockwise, i.e. negative direction)
      float64 rotatedImageX =
        cosAngle * translatedImageX
        + sinAngle * translatedImageY;

      float64 rotatedImageY =
        - sinAngle * translatedImageX
        + cosAngle * translatedImageY;

      // Translate back.
      xcoord = static_cast<int32>(floor(0.5
                                        + rotatedImageX
                                        + halfImageWidth ));
      ycoord = static_cast<int32>(floor(0.5
                                        + rotatedImageY
                                        + halfImageHeight ));
   }
   return MC2Point( xcoord, ycoord );
}

MC2Point
CosLatProjection::getGlobalPoint( const MC2Coordinate& coord ) const
{
   // See formula in getGlobalCoordinate

   int32 xcoord, ycoord;

   if( m_rotationAngle == 0 ) {
      // xcoord
      xcoord = int32(rint(coord.lon * m_xscale));

      // ycoord
      ycoord = int32( rint( m_height - 1 - coord.lat * m_yscale ) );
   } else {
      xcoord = 0;
      ycoord = 0;
   }
   return MC2Point( xcoord, ycoord );
}

MC2Coordinate
CosLatProjection::getGlobalCoordinate( const MC2Point& point ) const
{
   /*
    * The following formula is used to convert from point to lat/lon and vice
    * versa.
    * For lat <-> y:
    *    lat = (height - 1 - Y ) / yscale)
    *    y = height - 1 - lat * yscale
    * For lon <-> x:
    *    lon = x / m_xscale
    *    x = lon * m_xscale
    */
   int32 lat, lon;

   lat = int32( rint(( ((m_height - 1 - point.getY()) / m_yscale) ) ) );
   lon = int32( rint( ( (point.getX() / m_xscale) ) ) );

   return MC2Coordinate( lat, lon );
}

MC2Coordinate
CosLatProjection::getCoordinate( const MC2Point& point ) const
{
   int32 lat, lon;

   lat = int32( rint(
            ( ((m_height - 1 - point.getY()) / m_yscale) +
              m_bbox.getMinLat() ) ) );
   lon = int32( rint( ( (point.getX() / m_xscale) + m_bbox.getMinLon() ) ) );

   return MC2Coordinate( lat, lon );
}

int32
CosLatProjection::getLatDiff( int32 y ) const
{
   return int32( rint( y / m_yscale ) );
}

int32
CosLatProjection::getLonDiff( int32 x ) const
{
   return int32( rint( x / m_xscale ) );
}

uint32
CosLatProjection::getSizeInPacket() const
{
   return 4 + 16 + 16 + 4 + 4 + 4;
}

const MC2BoundingBox&
CosLatProjection::getBoundingBox() const
{
   return m_bbox;
}

const MC2BoundingBox&
CosLatProjection::getLargerBoundingBox() const
{
   return m_bbox;
}

uint32
CosLatProjection::getScaleLevel() const
{
   return MapUtility::getScaleLevel( m_bbox,
                                     m_width,
                                     m_height );
}

// Cylindrical projection

const int CylindricalProjection::NBR_PIXELS = 180;
const int CylindricalProjection::NBR_ZOOM_LEVELS = 15;

CylindricalProjection::CylindricalProjection(
   int xPixel,
   int yPixel,
   int zoomLevel,
   int nbrPixels,
   DrawingProjection::projection_t type )
   : DrawingProjection( type, MC2Point(nbrPixels,nbrPixels) ),
     m_latSquares( 0 ),
     m_lonSquares( 0 ),
     m_xPixel( xPixel ),
     m_yPixel( yPixel ),
     // set range 0 to max zoom levels
     m_zoomLevel( zoomLevel ),
     m_nbrPixels( nbrPixels ),
     m_radius( 0.0 )
{

   // Set nbr squares in latitude and longitude
   const int factor = 10;
   for (int i = 0; i < NBR_ZOOM_LEVELS; ++i) {
      int n = int(factor * pow( double(2), i ) );
      m_squareSizes.push_back( pair<int, int>( n, n ) );
   }
}

int
CylindricalProjection::getNbrZoomlevels() const
{
   return m_squareSizes.size();
}

vector< pair<int, int> >
CylindricalProjection::getSquareSizes() const
{
   return m_squareSizes;
}

void
CylindricalProjection::createSquare()
{
   // Set the status

   if( m_zoomLevel < 1 || m_zoomLevel > NBR_ZOOM_LEVELS ) {
      m_status = StringTableUTF8::NOTOK;
   } else {
      m_latSquares = m_squareSizes[m_zoomLevel-1].first;
      m_lonSquares = m_squareSizes[m_zoomLevel-1].second;
      m_radius = double(m_lonSquares * m_nbrPixels) / 2 / M_PI;

      if( (m_xPixel % m_nbrPixels) != 0 ) {
         m_status = StringTableUTF8::NOTOK;
      } else if( (m_yPixel % m_nbrPixels) != 0 ) {
         m_status = StringTableUTF8::NOTOK;
      } else if( m_xPixel < (-m_lonSquares*m_nbrPixels/2) ) {
         m_status = StringTableUTF8::NOTOK;
      } else if( m_xPixel > (m_lonSquares*m_nbrPixels/2-m_nbrPixels) ) {
         m_status = StringTableUTF8::NOTOK;
      } else if( m_yPixel < (-m_latSquares*m_nbrPixels/2) ) {
         m_status = StringTableUTF8::NOTOK;
      } else if( m_yPixel > (m_latSquares*m_nbrPixels/2-m_nbrPixels) ) {
         m_status = StringTableUTF8::NOTOK;
      } else {
         m_status = StringTableUTF8::OK;
      }
   }
}

bool CylindricalProjection::isValidPixelSize( uint32 pixelSize ) {
   // Even and larger than 31
   if ( pixelSize % 2 == 0 &&
        pixelSize >= 32 ) {
      return true;
   }
   return false;
}

void
CylindricalProjection::createBoundingBox()
{
   int xIndex =
      int( ( m_xPixel + m_lonSquares * m_nbrPixels / 2 )
           / m_nbrPixels );
   int yIndex =
      int( ( -(m_yPixel+m_nbrPixels)
             + m_latSquares * m_nbrPixels / 2 )  / m_nbrPixels);

   // Lower left coordinate
   int lowerXPixel =
      ( -m_lonSquares * m_nbrPixels / 2 ) + m_nbrPixels * xIndex;
   int lowerYPixel =
      int( m_latSquares * m_nbrPixels / 2 ) - m_nbrPixels * (yIndex+1);
   MC2Point lowerPoint( lowerXPixel, lowerYPixel );
   MC2Coordinate lowerCoord = getGlobalCoordinate( lowerPoint );

   // Upper right coordinate
   int upperXPixel =
      ( -m_lonSquares * m_nbrPixels / 2 ) + m_nbrPixels * ( xIndex + 1 );
   int upperYPixel =
      int( m_latSquares * m_nbrPixels / 2 ) - m_nbrPixels * yIndex;

   MC2Point upperPoint( upperXPixel, upperYPixel );
   MC2Coordinate upperCoord = getGlobalCoordinate( upperPoint );

   m_bbox.setMaxLat( upperCoord.lat );
   m_bbox.setMaxLon( upperCoord.lon );
   m_bbox.setMinLat( lowerCoord.lat );
   m_bbox.setMinLon( lowerCoord.lon );

   m_bbox.updateCosLat();

   m_largerBBox.setMaxLat(
      upperCoord.lat + getLatDiff( m_nbrPixels / 2 ) );
   m_largerBBox.setMaxLon(
      upperCoord.lon + getLonDiff( m_nbrPixels / 2 ) );
   m_largerBBox.setMinLat(
      lowerCoord.lat - getLatDiff( m_nbrPixels / 2 ) );
   m_largerBBox.setMinLon(
      lowerCoord.lon - getLonDiff( m_nbrPixels / 2 ) );

   m_largerBBox.updateCosLat();
}

const MC2BoundingBox&
CylindricalProjection::getBoundingBox() const
{
   return m_bbox;
}

const MC2BoundingBox&
CylindricalProjection::getLargerBoundingBox() const
{
   return m_largerBBox;
}

// Braun's cylindrical projection

BraunProjection::BraunProjection( int xPixel,
                                  int yPixel,
                                  int zoomLevel,
                                  int nbrPixels )
      : CylindricalProjection( xPixel,
                               yPixel,
                               zoomLevel,
                               nbrPixels,
                               DrawingProjection::braunProjection )
{
   init();
}

void
BraunProjection::init()
{
   createSquare();
   createBoundingBox();
}

void
BraunProjection::save( Packet* p, int& pos ) const
{
   // Write the projection type
   p->incWriteLong( pos, DrawingProjection::braunProjection );

   // Write the bounding box
   p->incWriteBBox( pos, m_bbox );

   // Write the x pixel
   p->incWriteLong( pos, m_xPixel );

   // Write the y pixel
   p->incWriteLong( pos, m_yPixel );

   // Write the zoom level
   p->incWriteLong( pos, m_zoomLevel );

   // Write the nbr of pixels
   p->incWriteLong( pos, m_nbrPixels );
}

MC2Point
BraunProjection::getPoint( const MC2Coordinate& coord ) const
{
   double lat = double( coord.lat * GfxConstants::invRadianFactor );
   double lon = double( coord.lon * GfxConstants::invRadianFactor );

   double x = double( lon * m_radius );
   double y = double( 2.0 * m_radius * tan( double( lat / 2 ) ) );

   double minLat = double(m_bbox.getMinLat() * GfxConstants::invRadianFactor);
   double minLon = double(m_bbox.getMinLon() * GfxConstants::invRadianFactor);

   double minX = minLon * m_radius;
   double minY = 2.0 * m_radius * tan( double( minLat / 2 ) );

   int32 xResult = int32( rint( x - minX ) );
   int32 yResult = int32( rint( y - minY ) );

   return MC2Point( xResult, m_nbrPixels - yResult );
}

MC2Point
BraunProjection::getGlobalPoint( const MC2Coordinate& coord ) const
{
   double lat = double( coord.lat * GfxConstants::invRadianFactor );
   double lon = double( coord.lon * GfxConstants::invRadianFactor );

   double x = lon * m_radius;
   double y = 2.0 * m_radius * tan( double( lat / 2 ) );

   int32 xResult = int32( rint( x ) );
   int32 yResult = int32( rint( y ) );

   return MC2Point( xResult, yResult );
}

MC2Coordinate
BraunProjection::getCoordinate( const MC2Point& point ) const
{
   double lat = 2 * atan( double(point.getY()) / 2 / m_radius );
   double lon = double( point.getX() ) / m_radius;

   double latMC2 = double( lat * GfxConstants::radianFactor );
   double lonMC2 = double( lon * GfxConstants::radianFactor );

   int32 latResult = int32( rint( latMC2 - double( m_bbox.getMinLat() ) ) );
   int32 lonResult = int32( rint( lonMC2 - double( m_bbox.getMinLon() ) ) );

   return MC2Coordinate( latResult, lonResult );
}

MC2Coordinate
BraunProjection::getGlobalCoordinate( const MC2Point& point ) const
{
   double lat = 2 * atan( double(point.getY()) / 2 / m_radius );
   double lon = double( point.getX() ) / m_radius;

   int32 latMC2 = int32( rint( lat * GfxConstants::radianFactor ) );
   int32 lonMC2 = int32( rint( lon * GfxConstants::radianFactor ) );

   return MC2Coordinate( latMC2, lonMC2 );
}

int32
BraunProjection::getLatDiff( int32 y ) const
{
   int diffMax = 0;
   MC2Coordinate minCoord = MC2Coordinate( m_bbox.getMinLat(),
                                           m_bbox.getMinLon() );
   MC2Point minPoint = getGlobalPoint( minCoord );
   MC2Point newMinPoint = MC2Point( minPoint.getX() - y,
                                    minPoint.getY() - y );
   MC2Coordinate newMinCoord = getGlobalCoordinate( newMinPoint );

   MC2Coordinate maxCoord = MC2Coordinate( m_bbox.getMaxLat(),
                                           m_bbox.getMaxLon() );
   MC2Point maxPoint = getGlobalPoint( maxCoord );
   MC2Point newMaxPoint = MC2Point( maxPoint.getX() + y,
                                    maxPoint.getY() + y );
   MC2Coordinate newMaxCoord = getGlobalCoordinate( newMaxPoint );

   if( (minCoord.lat - newMinCoord.lat) > diffMax ) {
      diffMax = minCoord.lat - newMinCoord.lat;
   }  else if( (newMaxCoord.lat - maxCoord.lat) > diffMax ) {
      diffMax = newMaxCoord.lat - maxCoord.lat;
   }

   return diffMax;
}

int32
BraunProjection::getLonDiff( int32 x ) const
{
   int diffMax = 0;

   MC2Coordinate minCoord = MC2Coordinate( m_bbox.getMinLat(),
                                           m_bbox.getMinLon() );
   MC2Point minPoint = getGlobalPoint( minCoord );
   MC2Point newMinPoint = MC2Point( minPoint.getX() - x,
                                    minPoint.getY() - x );
   MC2Coordinate newMinCoord = getGlobalCoordinate( newMinPoint );

   MC2Coordinate maxCoord = MC2Coordinate( m_bbox.getMaxLat(),
                                           m_bbox.getMaxLon() );
   MC2Point maxPoint = getGlobalPoint( maxCoord );
   MC2Point newMaxPoint = MC2Point( maxPoint.getX() + x,
                                    maxPoint.getY() + x );
   MC2Coordinate newMaxCoord = getGlobalCoordinate( newMaxPoint );

   if( (minCoord.lon - newMinCoord.lon) > diffMax ) {
      diffMax = minCoord.lon - newMinCoord.lon;
   }  else if( (newMaxCoord.lon - maxCoord.lon) > diffMax ) {
      diffMax = newMaxCoord.lon - maxCoord.lon;
   }

   return diffMax;
}

uint32
BraunProjection::getSizeInPacket() const
{
   return 4 + 16 + 4 + 4 + 4 + 4;
}

uint32
BraunProjection::getScaleLevel() const
{
   switch( m_zoomLevel ) {
      case 1:
         return 0;
      break;
      case 2:
         return 1;
      break;
      case 3:
         return 1;
      break;
      case 4:
         return 2;
      break;
      case 5:
         return 2;
      break;
      case 6:
         return 2;
      break;
      case 7:
         return 2;
      break;
      case 8:
         return 3;
      break;
      case 9:
         return 3;
      break;
      case 10:
         return 4;
      break;
      case 11:
         return 5;
      break;
      case 12:
         return 6;
      break;
      case 13:
         return 7;
      break;
      case 14:
         return 8;
      break;
      case 15:
         return 9;
      break;
      default:
         return 10;
         break;
   }

   // Should not happen
   return MAX_UINT32;
}

// Mercator projection
MercatorProjection::MercatorProjection( int xPixel,
                                        int yPixel,
                                        int zoomLevel,
                                        int nbrPixels )
      : CylindricalProjection( xPixel,
                               yPixel,
                               zoomLevel,
                               nbrPixels,
                               DrawingProjection::mercatorProjection )
{
   init();
}

void
MercatorProjection::init()
{
   createSquare();
   createBoundingBox();
   // Init the zoom levels used by j2me-client.
   uint32 j2meZooms [] = { 4, 7, 9, 11, 13, 15 };
   m_j2me_zooms.insert( &j2meZooms[0],
                        &j2meZooms[0] +
                        sizeof(j2meZooms)/sizeof(j2meZooms[0]));
}

void
MercatorProjection::save( Packet* p, int& pos ) const
{
   // Write the projection type
   p->incWriteLong( pos, DrawingProjection::mercatorProjection );

   // Write the bounding box
   p->incWriteBBox( pos, m_bbox );

   // Write the x pixel
   p->incWriteLong( pos, m_xPixel );

   // Write the y pixel
   p->incWriteLong( pos, m_yPixel );

   // Write the zoom level
   p->incWriteLong( pos, m_zoomLevel );

   // Write the nbr of pixels
   p->incWriteLong( pos, m_nbrPixels );
}

MC2Point
MercatorProjection::getPoint( const MC2Coordinate& coord ) const
{
   double lat = double(coord.lat * GfxConstants::invRadianFactor);
   double lon = double(coord.lon * GfxConstants::invRadianFactor);

   double x = m_radius * lon;
   double y =
      double(m_radius) * log( tan( lat ) + double( 1.0 / cos( lat ) ) );

   double minLat = double(m_bbox.getMinLat() * GfxConstants::invRadianFactor);
   double minLon = double(m_bbox.getMinLon() * GfxConstants::invRadianFactor);

   double minX = m_radius * minLon;
   double minY =
      m_radius * log( tan( minLat ) + double( 1.0 / cos( minLat ) ) );

   int32 xResult = int32( rint( x - minX ) );
   int32 yResult = int32( rint( y - minY ) );

   return MC2Point( xResult, m_nbrPixels - yResult );
}

MC2Point
MercatorProjection::getGlobalPoint( const MC2Coordinate& coord ) const
{
   double lat = double(coord.lat * GfxConstants::invRadianFactor);
   double lon = double(coord.lon * GfxConstants::invRadianFactor);

   double x = m_radius * lon;
   double y = m_radius * log( tan( lat ) + double( 1.0 / cos( lat ) ) );

   int32 xResult = int32( rint( x ) );
   int32 yResult = int32( rint( y ) );

   return MC2Point( xResult, yResult );
}

MC2Coordinate
MercatorProjection::getCoordinate( const MC2Point& point ) const
{
   double lat = atan( sinh( double(point.getY() / m_radius ) ) );
   double lon = double( point.getX() ) / m_radius;

   double latMC2 = double( lat * GfxConstants::radianFactor );
   double lonMC2 = double( lon * GfxConstants::radianFactor );

   int32 latResult = int32( rint( latMC2 - double(m_bbox.getMinLat() ) ) );
   int32 lonResult = int32( rint( lonMC2 - double(m_bbox.getMinLon() ) ) );

   return MC2Coordinate( latResult, lonResult );
}

MC2Coordinate
MercatorProjection::getGlobalCoordinate( const MC2Point& point ) const
{
   double lat = atan( sinh( double(point.getY() / m_radius ) ) );
   double lon = double( point.getX() ) / m_radius;

   int32 latMC2, lonMC2;
   latMC2 = int32( rint( lat * GfxConstants::radianFactor ) );
   lonMC2 = int32( rint( lon * GfxConstants::radianFactor ) );

   return MC2Coordinate( latMC2, lonMC2 );
}

int32
MercatorProjection::getLatDiff( int32 y ) const
{
   int diffMax = 0;
   MC2Coordinate minCoord = MC2Coordinate( m_bbox.getMinLat(),
                                           m_bbox.getMinLon() );
   MC2Point minPoint = getGlobalPoint( minCoord );
   MC2Point newMinPoint = MC2Point( minPoint.getX() - y,
                                    minPoint.getY() - y );
   MC2Coordinate newMinCoord = getGlobalCoordinate( newMinPoint );

   MC2Coordinate maxCoord = MC2Coordinate( m_bbox.getMaxLat(),
                                           m_bbox.getMaxLon() );
   MC2Point maxPoint = getGlobalPoint( maxCoord );
   MC2Point newMaxPoint = MC2Point( maxPoint.getX() + y,
                                    maxPoint.getY() + y );
   MC2Coordinate newMaxCoord = getGlobalCoordinate( newMaxPoint );

   if( (minCoord.lat - newMinCoord.lat) > diffMax ) {
      diffMax = minCoord.lat - newMinCoord.lat;
   }  else if( (newMaxCoord.lat - maxCoord.lat) > diffMax ) {
      diffMax = newMaxCoord.lat - maxCoord.lat;
   }

   return diffMax;
}

int32
MercatorProjection::getLonDiff( int32 x ) const
{
   int diffMax = 0;

   MC2Coordinate minCoord = MC2Coordinate( m_bbox.getMinLat(),
                                           m_bbox.getMinLon() );
   MC2Point minPoint = getGlobalPoint( minCoord );
   MC2Point newMinPoint = MC2Point( minPoint.getX() - x,
                                    minPoint.getY() - x );
   MC2Coordinate newMinCoord = getGlobalCoordinate( newMinPoint );

   MC2Coordinate maxCoord = MC2Coordinate( m_bbox.getMaxLat(),
                                           m_bbox.getMaxLon() );
   MC2Point maxPoint = getGlobalPoint( maxCoord );
   MC2Point newMaxPoint = MC2Point( maxPoint.getX() + x,
                                    maxPoint.getY() + x );
   MC2Coordinate newMaxCoord = getGlobalCoordinate( newMaxPoint );

   if( (minCoord.lon - newMinCoord.lon) > diffMax ) {
      diffMax = minCoord.lon - newMinCoord.lon;
   }  else if( (newMaxCoord.lon - maxCoord.lon) > diffMax ) {
      diffMax = newMaxCoord.lon - maxCoord.lon;
   }

   return diffMax;
}

uint32
MercatorProjection::getSizeInPacket() const
{
   return 4 + 16 + 4 + 4 + 4 + 4;
}

uint32
MercatorProjection::getScaleLevel() const
{
   switch( m_zoomLevel ) {
      case 1:
         return 0;
      break;
      case 2:
         return 0;
      break;
      case 3:
         return 1;
      break;
      case 4:
         return 2;
      break;
      case 5:
         return 2;
      break;
      case 6:
         return 3;
      break;
      case 7:
         return 3;
      break;
      case 8:
         return 4;
      break;
      case 9:
         return 5;
      break;
      case 10:
         return 5;
      break;
      case 11:
         return 6;
      break;
      case 12:
         return 7;
      break;
      case 13:
         return 8;
      break;
      case 14:
         return 9;
      break;
      case 15:
         return 10;
      break;
      default:
         return 10;
         break;
   }

   // Should not happen
   return MAX_UINT32;
}