text:
/* externally visible structures and functions for peers */
#include "peers.h"
/* externally visible structures and functions for peer groups */
#include "peergroup.h"
/* required for logging functions */
#include "../Util/log.h"
/* needed for reading and saving configuration */
#include "../Config/configdefaults.h"
#include "../Config/configfile.h"

/* needed for ADDR_MAX_CHARS and MAX_PEER_IDS */
#include "../site_defaults.h"

/* required for TRUE/FALSE defines  */
#include "../Util/bgpmon_defaults.h"

/* needed for address management  */
#include "../Util/address.h"

/* needed for malloc and free */
#include <stdlib.h>
/* needed for strncpy */
#include <string.h>
/* needed for system error codes */
#include <errno.h>
/* needed for system types such as time_t */
#include <sys/types.h>
/* needed for time function */
#include <time.h>
/* needed for pthread related functions */
#include <pthread.h>
/* needed for generatePeeringString */
#include "../XML/xml.h"
/* needed for createLabelingStruct*/
#include "../Labeling/label.h"
/* needed for bgp states*/
#include "bgpstates.h"
/* needed for LOG_INFO*/
#include <syslog.h>

//#define DEBUG

/*--------------------------------------------------------------------------------------
 * Purpose: Initialize the peer groups.
 * Input: none
 * Output: returns 0 on success, 1 on failure
 * He Yan @ July 22, 2008
 * -------------------------------------------------------------------------------------*/
int initPeerGroupsSettings()
{
	// initialize the list of peer groups
	int i;
	for( i = 0; i < MAX_PEER_GROUP_IDS; i++)
		PeerGroups[i] = NULL;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Read the peer groups settings from the config file.
 * Input: none
 * Output: returns 0 on success, 1 on failure
 * He Yan @ July 22, 2008
 * -------------------------------------------------------------------------------------*/
int readPeerGroupsSettings()
{
	debug(__FUNCTION__, "readPeerGroupsSettings" );
	int 	err = 0;	// indicates whether read was successful
	int 	valid;		// is the current peer configuration valid
	char	*name = NULL; // group's name
	int 	result; 	// indicates whether XML read was successful

	// get the count of peer groups
	int peerGroupsCount = getConfigListCount(XML_PEER_GROUPS_PATH);
#ifdef DEBUG
	debug(__FUNCTION__, "found %d configured peer groups", peerGroupsCount);
#endif

	// check if the count of peers exceeds MAX_PEER_IDS. If so, trim it.
	if(peerGroupsCount > MAX_PEER_GROUP_IDS)
	{
		peerGroupsCount = MAX_PEER_GROUP_IDS;
		log_warning("Configured peer groups(%d) exceeds maximum allowable number of peers groups(%d).", peerGroupsCount, MAX_PEER_GROUP_IDS);
		log_warning("using only first %d configured peer groups", MAX_PEER_GROUP_IDS);
	}

	// read each peer group's configuration and create the peer group structure
	int i;
	for(i = 0; i < peerGroupsCount; i++)
	{
		PConfiguration peerConf;
		valid = readPeerConf( &peerConf, XML_PEER_GROUPS_PATH, i );

		// read group name
		name = NULL;
		result = getConfigValueFromListAsString(&name, XML_PEER_GROUPS_PATH, XML_PEER_GROUP_NAME_TAG, i, PEER_GROUP_MAX_CHARS);
		if ( ( result == CONFIG_INVALID_ENTRY ) || ( result == CONFIG_NO_ENTRY ) )
		{
			log_warning("Invalid configuration of peer group %d name.", i);
			valid = FALSE;
		}

		// if configuration is valid, create peer group struct
		if (valid == TRUE)
		{
			//create the peer group structure
			int newPeerGroupID = createPeerGroupStruct(peerConf, name);
			if (newPeerGroupID == -1)
			{
				err = 1;
				log_warning("Unable to create structure for peer group %d", i);
			}
			else
			{
				log_msg("created new peer group with id (%d)", newPeerGroupID);
			#ifdef DEBUG
				printPeerGroupSettings(newPeerGroupID);
			#endif
			}
		}
		else
			err = 1;

		// free name if defined
		if (name != NULL)
			free(name);
	}
	return err;

}

/*--------------------------------------------------------------------------------------
 * Purpose: Save the peer groups settings to the config file.
 * Input:  none
 * Output: returns 0 on success, 1 on failure
 * He Yan @ July 22, 2008
 * -------------------------------------------------------------------------------------*/
int savePeerGroupsSettings()
{
	int err = 0;
	int i;

	// open the peer groups list
	if (openConfigElement(XML_PEER_GROUP_LIST_TAG))
	{
		err = 1;
		log_warning("Failed to save peer groups list tag to config file.");
	}

	for(i = 0; i < MAX_PEER_GROUP_IDS; i++)
	{
		if( PeerGroups[i] != NULL && i > 0) // skip default group
		{
			// open a peer group
			if (openConfigElement(XML_PEER_GROUP_TAG))
			{
				err = 1;
				log_warning("Failed to save peer group tag to config file.");
			}

			// write peer group's name
			if ( setConfigValueAsString(XML_PEER_GROUP_NAME_TAG, PeerGroups[i]->name) )
			{
				err = 1;
				log_warning("Failed to save peer group's name to config file.");
			}
			// write a peer group
			err = saveOnePeerSetting(PeerGroups[i]->configuration);

			// close a peer group
			if (closeConfigElement(XML_PEER_GROUP_TAG))
			{
				err = 1;
				log_warning("Failed to save peer group tag to config file.");
			}
		}
	}

	// close the peer groups list
	if (closeConfigElement(XML_PEER_GROUP_LIST_TAG))
	{
		err = 1;
		log_warning("Failed to save peer groups list tag to config file.");
	}
	return err;

}

/*--------------------------------------------------------------------------------------
 * Purpose: print the peer group settings
 * Input:  the peer group ID
 * Output: NULL
 * He Yan @ July 22, 2008
 * -------------------------------------------------------------------------------------*/
void printPeerGroupSettings(int peerGroupID)
{
	debug(__FUNCTION__, "Peer Group %d: name is %s", peerGroupID, getPeerGroupName(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: Local Addr: %s", peerGroupID, getPeerGroupLocalAddress(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: Local port set to %d", peerGroupID, getPeerGroupLocalPort(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: Local BGP version set to %d", peerGroupID, getPeerGroupLocalBGPVersion(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: Local BGP AS number set to %d", peerGroupID, getPeerGroupLocalASNum(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: Local BGP hold time set to %d", peerGroupID, getPeerGroupLocalHoldTime(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: Local BGP ID set to %d", peerGroupID, getPeerGroupLocalBGPID(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: remote BGP version set to %d", peerGroupID, getPeerGroupRemoteBGPVersion(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: remote BGP AS number set to %d", peerGroupID, getPeerGroupRemoteASNum(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: remote min hold time set to %d", peerGroupID, getPeerGroupRemoteHoldTime(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: remote BGP ID set to %d", peerGroupID, getPeerGroupRemoteBGPID(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: MD5 passwd: %s", peerGroupID, getPeerGroupMD5Passwd(peerGroupID) );
	debug(__FUNCTION__, "Peer Group %d: label action set to %d", peerGroupID, getPeerGroupLabelAction(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: route refresh action set to %d", peerGroupID, getPeerGroupRouteRefreshAction(peerGroupID));
	debug(__FUNCTION__, "Peer Group %d: group ID set to %s", peerGroupID, PeerGroups[peerGroupID]->configuration->groupID);
	if(getPeerGroupEnabledFlag(peerGroupID) == TRUE)
		debug(__FUNCTION__, "Peer Group %d is enabled", peerGroupID);
	else
		debug(__FUNCTION__, "Peer Group %d is disabled", peerGroupID);
}

/*--------------------------------------------------------------------------------------
 * Purpose: find ID of a peer group given group name
 * Input: group name in string
 * Output: ID of the peer group
 * Note: If the peer group with specified name is not exsiting, return -1.
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int findPeerGroupID(char *groupName)
{
	int i;
	for(i = 0; i < MAX_PEER_GROUP_IDS; i++)
	{
		if( PeerGroups[i] != NULL && !strcmp(PeerGroups[i]->name, groupName) )
			return PeerGroups[i]->ID;
	}
	return -1;
}

/*--------------------------------------------------------------------------------------
 * Purpose: create the default peer group
 * Input:
 * Output: pointer to peer configuration or NULL if creation failed
 * He Yan @ July 22, 2008
 * -------------------------------------------------------------------------------------*/
int createDefaultPeerGroup()
{
	PConfiguration peerConf = malloc( sizeof( struct ConfigurationStruct ));
	if( peerConf == NULL )
	{
		log_err( "createDefaultPeerGroup: malloc failed" );
		return -1;
	}
	memset( peerConf, 0, sizeof( struct ConfigurationStruct ));
	strcpy( peerConf->localSettings.addr, MONITOR_ADDRESS );
	peerConf->localSettings.port = MONITOR_PORT;
	peerConf->localSettings.AS2 = 0;
	peerConf->localSettings.BGPVer = MONITOR_BGP_VERSION;
	peerConf->localSettings.holdtime = MONITOR_ANNOUNCE_HOLDTIME;
	peerConf->localSettings.BGPID = 0;

	peerConf->remoteSettings.port = PEER_PORT;
	peerConf->remoteSettings.AS2 = 0;
	peerConf->remoteSettings.MinHoldtime = PEER_MIN_HOLDTIME;
	peerConf->remoteSettings.BGPVer = PEER_BGP_VERSION;
	peerConf->remoteSettings.BGPID = 0;

	peerConf->enabled = PEERS_ENABLED;
	peerConf->routeRefreshAction = PEERS_RR_ACTION;
	peerConf->labelAction= PEERS_LABEL_ACTION;

	peerConf->numOfReceiveCaps = 0;
	peerConf->numOfAnnCaps = 0;
	peerConf->groupID = -1;

	PPeerGroup pg = malloc( sizeof( struct PeerGroupStruct ) );
	if( pg == NULL )
	{
		log_err("createDefaultPeerGroup: malloc failed");
		return -1;
	}

	memset(pg, 0, sizeof( struct PeerGroupStruct) );

	// peer group ID
	pg->ID = 0;
	// peer group name
	strcpy(pg->name, DEFAULT_PEER_GROUP_NAME);
	pg->configuration = peerConf;

	PeerGroups[0] = pg;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Create a peer group structure
 * Input:  the peer configuration struture and the group name
 * Output: id of the new peer group or -1 if creation failed
 * He Yan @ July 22, 2008
 * -------------------------------------------------------------------------------------*/
int createPeerGroupStruct( PConfiguration config, char *name  )
{

	// check if it is existing
	if( findPeerGroupID(name) != -1 )
	{
	 	log_err("Unable to create new peer group as it is already existing");
		return -1;
	}
	// find a empty slot for this new peer group
	int i;
	for(i = 0; i < MAX_PEER_GROUP_IDS; i++)
	{
		if(PeerGroups[i] == NULL)
			break;
	}

	// if the number of peer groups exceeds MAX_PEER_GROUP_IDS, return -1
	if( i == MAX_PEER_GROUP_IDS )
	{
	 	log_err("Unable to create new peer group, max peer groups exceeded");
		return -1;
	}

	// Returns a new Session_structp or NULL if not enough memory.
	PPeerGroup pg = malloc( sizeof( struct PeerGroupStruct ) );
	if( pg == NULL )
	{
		log_err("createPeerGroupStruct: malloc failed");
		return -1;
	}

	memset(pg, 0, sizeof( struct PeerGroupStruct) );

	// peer group ID
	pg->ID = i;
	// peer group name
	if( name != NULL )
	{
		strcpy(pg->name, name);
	}
	pg->configuration = config;

	PeerGroups[i] = pg;
 	return i;

}

/*--------------------------------------------------------------------------------------
 * Purpose: create a peer group called by CLI.
 * Input:  name - the group name
 * Output: id of the new peer/peergoup or -1 if creation failed
 * He Yan @ July 22, 2008
 * -------------------------------------------------------------------------------------*/
int createPeerGroup( char *name )
{
	PConfiguration peerConf = createPeerConf( NULL, -1 );
	if( peerConf != NULL)
	{
		int peerGoupID = createPeerGroupStruct( peerConf, name );
		if( peerGoupID == -1 )
		{
			log_err( "Creation of peer group structure failed" );
			return -1;
		}
		return peerGoupID;
	}
	else
		return -1;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get an array of IDs of all peer groups
 * Input: a pointer to an array
 * Output: the length of the array
 * Note: 1. The caller doesn't need to allocate memory.
 *	 2. The caller must free the array after using it.
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getAllPeerGroupsIDs(int **peerGroupIDs)
{
	int i;
	// get a count of peer groups
	int peerGroupCount = 0;
	for(i = 0; i < MAX_PEER_GROUP_IDS; i++)
	{
		if( PeerGroups[i] != NULL )
			peerGroupCount++;
	}

	// allocate memory for the resulting ids
	int *IDs = malloc(sizeof(int)*peerGroupCount);
	if (IDs == NULL)
	{
		log_warning("getAllPeerGroupsIDs: Unable to allocate memory");
		return 0;
	}

	// note is possible some peer groups were added since we counted above
	int actualPeerGroups = 0;
	for(i = 0; i < MAX_PEER_GROUP_IDS; i++)
	{
		if( (PeerGroups[i] != NULL ) && (actualPeerGroups <= peerGroupCount ) )
		{
			IDs[actualPeerGroups] = i;
			actualPeerGroups++;
		}
	}
	*peerGroupIDs = IDs;
	return actualPeerGroups;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Print Peer Groups Array
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
void printAllPeerGroups()
{
	int i;
	for(i = 0; i < MAX_PEER_GROUP_IDS; i++)
	{
		if( PeerGroups[i] != NULL )
		{
			log_msg("PeerGroup %d, name %s", PeerGroups[i]->ID, PeerGroups[i]->name);
		}
	}
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer group's name
 * Input:	the peer group's ID
 * Output: the name of the peer group or NULL
 * Note: The caller doesn't need to free memory.
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
char * getPeerGroupName(int peerGroupID)
{
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupName: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return NULL;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupName: couldn't find a peer group with ID:%d", peerGroupID);
		return NULL;
	}
	return PeerGroups[peerGroupID]->name;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the remote AS number of the peer group
 * Input:   the peer group's ID
 * Output: the peer group's remote AS number
 *         or -1 if there is no peer group with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
u_int32_t getPeerGroupRemoteASNum( int peerGroupID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupRemoteASNum: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return 0;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupRemoteASNum: couldn't find a peer group with ID:%d", peerGroupID);
		return 0;
	}
	// if the remote AS number is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->remoteSettings.AS2 == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->remoteSettings.AS2;
	else
		return PeerGroups[peerGroupID]->configuration->remoteSettings.AS2;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's remote AS number
 * Input:	the peer's ID and AS number
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupRemoteASNum( int peerGroupID, u_int32_t AS )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("setPeerGroupRemoteASNum: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupRemoteASNum: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if the AS number changed
	if( PeerGroups[peerGroupID]->configuration->remoteSettings.AS2 == AS )
		return 0;

	// if changed, set it
	PeerGroups[peerGroupID]->configuration->remoteSettings.AS2 = AS;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's remote BGP version
 * Input:	the peer group's ID
 * Output: the remote BGP Versionn
 *         or -1 if there is no peer group with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupRemoteBGPVersion( int peerGroupID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupRemoteBGPVersion: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupRemoteBGPVersion: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the remote BGP version is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->remoteSettings.BGPVer == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->remoteSettings.BGPVer;
	else
		return PeerGroups[peerGroupID]->configuration->remoteSettings.BGPVer;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's remote BGP version
 * Input:	the peer group's ID and remote BGP version
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupRemoteBGPVersion( int peerGroupID, int version )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("setPeerGroupRemoteBGPVersion: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupRemoteBGPVersion: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if the supplied remote BGP version is different from current
	if( PeerGroups[peerGroupID]->configuration->remoteSettings.BGPVer== version )
		return 0;

	// if different, set it
	PeerGroups[peerGroupID]->configuration->remoteSettings.BGPVer = version;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's remote BGP ID
 * Input:	the peer group's ID
 * Output: the remote BGP ID
 *         or -1 if there is no peer with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
long long getPeerGroupRemoteBGPID(int peerGroupID)
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupRemoteBGPID: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupRemoteBGPID: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the remote BGP ID is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->remoteSettings.BGPID == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0)
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->remoteSettings.BGPID;
	else
		return PeerGroups[peerGroupID]->configuration->remoteSettings.BGPID;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's remote BGP ID
 * Input:	the peer group's ID and the remote BGP ID
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int SetPeerGroupRemoteBGPID( int peerGroupID, long long BGPID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("SetPeerGroupRemoteBGPID: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("SetPeerGroupRemoteBGPID: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if the supplied BGP ID is different from current
	if( PeerGroups[peerGroupID]->configuration->remoteSettings.BGPID == BGPID )
		return -1;

	// if different, set it
	PeerGroups[peerGroupID]->configuration->remoteSettings.BGPID = BGPID;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's remote hold time
 * Input:	the peer group's ID
 * Output: the remote hold time
 *         or -1 if there is no peer group with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupRemoteHoldTime( int peerGroupID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupRemoteHoldTime: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupRemoteHoldTime: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the remote hold time is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->remoteSettings.MinHoldtime== -1 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->remoteSettings.MinHoldtime;
	else
		return PeerGroups[peerGroupID]->configuration->remoteSettings.MinHoldtime;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's remote hold time
 * Input:	the peer group's ID and remote hold time
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupRemoteHoldTime( int peerGroupID, int holdTime )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("setPeerGroupRemoteHoldTime: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupRemoteHoldTime: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if the supplied holdtime is different from current
	if( PeerGroups[peerGroupID]->configuration->remoteSettings.MinHoldtime == holdTime )
		return 0;

	// if different, set it
	PeerGroups[peerGroupID]->configuration->remoteSettings.MinHoldtime = holdTime;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's MD5 password
 * Input:	the peer group's ID
 * Output: the MD5 password or NULL
 * Note: The caller doesn't need to free memory.
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
char * getPeerGroupMD5Passwd(int peerGroupID)
{
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupMD5Passwd: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return NULL;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupMD5Passwd: couldn't find a peer group with ID:%d", peerGroupID);
		return NULL;
	}

	// if the local address is not set, use the value from default group
	char *passwd = NULL;
	if( strlen(PeerGroups[peerGroupID]->configuration->remoteSettings.md5Passwd) == 0 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		passwd = PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->remoteSettings.md5Passwd;
	else
		passwd = PeerGroups[peerGroupID]->configuration->remoteSettings.md5Passwd;

	return passwd;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer group's MD5 password
 * Input:	the peer group's ID and the MD5 password in string
 * Output: 0 means success, -1 means failure
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupMD5Passwd( int peerGroupID, char *passwd )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("setPeerGroupMD5Passwd: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}

	// check if the peer group is defined
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupMD5Passwd: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if the supplied address is different from current
	if( strcmp(PeerGroups[peerGroupID]->configuration->remoteSettings.md5Passwd, passwd) == 0 )
		return 0;

	// if different, set it
	strncpy( PeerGroups[peerGroupID]->configuration->remoteSettings.md5Passwd, passwd, PASSWORD_MAX_CHARS);
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's local address
 * Input:	the peer group's ID
 * Output: the local address or NULL
 * Note: The caller doesn't need to free memory.
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
char * getPeerGroupLocalAddress(int peerGroupID)
{
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupLocalAddress: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return NULL;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupLocalAddress: couldn't find a peer group with ID:%d", peerGroupID);
		return NULL;
	}

	// if the local address is not set, use the value from default group
	char *addr = NULL;
	if( strlen(PeerGroups[peerGroupID]->configuration->localSettings.addr) == 0 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		addr = PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->localSettings.addr;
	else
		addr = PeerGroups[peerGroupID]->configuration->localSettings.addr;

	return addr;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer group's local address
 * Input:	the peer group's ID and the local addr in string
 * Output:  ADDR_VALID means address is valid and set successfully.
 *	    ADDR_ERR_INVALID_FORMAT means this is a invalid-format address
 *          ADDR_ERR_INVALID_ACTIVE means this is not a valid active address
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupLocalAddress( int peerGroupID, char *addr )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("setPeerGroupLocalAddress: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return ADDR_ERR_INVALID_FORMAT;
	}

	// check if the peer group is defined
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupLocalAddress: couldn't find a peer group with ID:%d", peerGroupID);
		return ADDR_ERR_INVALID_FORMAT;
	}

	// check if the supplied address is valid
	int result = checkAddress(addr, ADDR_PASSIVE);
	if(result != ADDR_VALID)
		return result;

	// check if the supplied address is different from current
	if( strcmp(PeerGroups[peerGroupID]->configuration->localSettings.addr, addr) == 0 )
		return ADDR_VALID;

	// if different, set it
	strncpy( PeerGroups[peerGroupID]->configuration->localSettings.addr, addr, ADDR_MAX_CHARS);
	return ADDR_VALID;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's local port
 * Input:	the peer group's ID
 * Output: the monitor side port
 *         or -1 if there is no peer with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupLocalPort(int peerGroupID)
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupLocalPort: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupLocalPort: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the local port is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->localSettings.port == 0 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->localSettings.port;
	else
		return PeerGroups[peerGroupID]->configuration->localSettings.port;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's local port
 * Input:	the peer group 's ID and the port
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupLocalPort( int peerGroupID, int port )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("setPeerGroupLocalPort: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupLocalPort: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}
	//  check if the port is valid
	if ( (port < 0) || (port > 65536) )
	{
		log_err("setPeerGroupLocalPort: invalid port number of %d", port);
		return -1;
	}

	// check if the supplied port is different from current
	if( PeerGroups[peerGroupID]->configuration->localSettings.port == port )
		return 0;

	// if different, set it
	PeerGroups[peerGroupID]->configuration->localSettings.port = port;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's local BGP ID
 * Input:	the peer group's ID
 * Output: the local BGP ID
 *         or -1 if there is no peer with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
long long getPeerGroupLocalBGPID(int peerGroupID)
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupLocalBGPID: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupLocalBGPID: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the local BGP ID is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->localSettings.BGPID == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0)
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->localSettings.BGPID;
	else
		return PeerGroups[peerGroupID]->configuration->localSettings.BGPID;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's local BGP ID
 * Input:	the peer group's ID and the local BGP ID
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int SetPeerGroupLocalBGPID( int peerGroupID, long long BGPID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("SetPeerGroupLocalBGPID: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("SetPeerGroupLocalBGPID: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if the supplied BGP ID is different from current
	if( PeerGroups[peerGroupID]->configuration->localSettings.BGPID == BGPID )
		return -1;

	// if different, set it
	PeerGroups[peerGroupID]->configuration->localSettings.BGPID = BGPID;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's local AS number
 * Input:	the peer group's ID
 * Output: the local AS number
 *         or -1 if there is no peer group with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
u_int32_t getPeerGroupLocalASNum( int peerGroupID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupLocalASNum: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return 0;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupLocalASNum: couldn't find a peer group with ID:%d", peerGroupID);
		return 0;
	}

	// if the local AS number is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->localSettings.AS2 == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->localSettings.AS2;
	else
		return PeerGroups[peerGroupID]->configuration->localSettings.AS2;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's local AS number
 * Input:	the peer group's ID and local AS number
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupLocalASNum( int peerGroupID, u_int32_t AS )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("setPeerGroupLocalASNum: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupLocalASNum: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if the supplied AS number is different from current
	if( PeerGroups[peerGroupID]->configuration->localSettings.AS2 == AS )
		return 0;

	// if different, set it
	PeerGroups[peerGroupID]->configuration->localSettings.AS2 = AS;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's local hold time
 * Input:	the peer group's ID
 * Output: the local hold time
 *         or -1 if there is no peer group with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupLocalHoldTime( int peerGroupID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupLocalHoldTime: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupLocalHoldTime: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the local hold time is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->localSettings.holdtime == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->localSettings.holdtime;
	else
		return PeerGroups[peerGroupID]->configuration->localSettings.holdtime;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's local hold time
 * Input:	the peer group's ID and local hold time
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupLocalHoldTime( int peerGroupID, int holdTime )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("setPeerGroupLocalHoldTime: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupLocalHoldTime: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if the supplied holdtime is different from current
	if( PeerGroups[peerGroupID]->configuration->localSettings.holdtime == holdTime )
		return 0;

	// if different, set it
	PeerGroups[peerGroupID]->configuration->localSettings.holdtime = holdTime;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's local BGP version
 * Input:	the peer group's ID
 * Output: the local BGP version
 *         or -1 if there is no peer group with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupLocalBGPVersion( int peerGroupID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupLocalBGPVersion: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupLocalBGPVersion: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the local BGP version is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->localSettings.BGPVer == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->localSettings.BGPVer;
	else
		return PeerGroups[peerGroupID]->configuration->localSettings.BGPVer;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's local BGP version
 * Input:	the peer group's ID and local BGP version
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupLocalBGPVersion( int peerGroupID, int version )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("setPeerGroupLocalHoldTime: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupLocalHoldTime: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if the supplied BGP version is different from current
	if( PeerGroups[peerGroupID]->configuration->localSettings.BGPVer== version )
		return 0;

	// if different, set it
	PeerGroups[peerGroupID]->configuration->localSettings.BGPVer = version;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer Group's label action
 * Input:	the peer group's ID
 * Output: the label action
 *         or -1 if there is no peer group with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupLabelAction( int peerGroupID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupLabelAction: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupLabelAction: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the label action is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->labelAction == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->labelAction;
	else
		return PeerGroups[peerGroupID]->configuration->labelAction;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the peer Group's label action
 * Input:	the peer's ID and label action
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupLabelAction( int peerGroupID, int labelAction )
{
	// check the peer group ID is valid
	if( peerGroupID >= MAX_PEER_GROUP_IDS )
	{
		log_err("setPeerGroupLabelAction: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupLabelAction: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if label action changes
	if( PeerGroups[peerGroupID]->configuration->labelAction == labelAction )
		return 0;

	// if changed ...
	log_msg("setPeerGroupLabelAction: from %d to %d", PeerGroups[peerGroupID]->configuration->labelAction, labelAction);
	PeerGroups[peerGroupID]->configuration->labelAction = labelAction;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get the peer group's route refresh action
 * Input:   the peer group's ID
 * Output: the route refresh action
 *         or -1 if there is no peer group with this ID
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupRouteRefreshAction( int peerGroupID )
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupRouteRefreshAction: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupRouteRefreshAction: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the route refresh action is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->routeRefreshAction == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->routeRefreshAction;
	else
		return PeerGroups[peerGroupID]->configuration->routeRefreshAction;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Set the route refresh action pf a peer group
 * Input:	the peer group's ID and route refresh action
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupRouteRefreshAction( int peerGroupID, int rrAction )
{
	// check the peer group ID is valid
	if( peerGroupID >= MAX_PEER_GROUP_IDS )
	{
		log_err("setPeerGroupRouteRefreshAction: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupRouteRefreshAction: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if RR action changes
	if( PeerGroups[peerGroupID]->configuration->routeRefreshAction == rrAction )
		return 0;

	// if changed ...
	log_msg("setPeerGroupRouteRefreshAction: from %d to %d", PeerGroups[peerGroupID]->configuration->routeRefreshAction, rrAction);
	PeerGroups[peerGroupID]->configuration->routeRefreshAction = rrAction;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: get the enabled flag of a peer group
 * Input:	the peer group's ID
 * Output: the enabled flag
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupEnabledFlag(int peerGroupID)
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupEnabledFlag: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupEnabledFlag: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// if the enabled flag is not set, use the value from default group
	if( PeerGroups[peerGroupID]->configuration->enabled == -1 && PeerGroups[peerGroupID]->configuration->groupID >=0 )
		return PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->enabled;
	else
		return PeerGroups[peerGroupID]->configuration->enabled;

}

/*--------------------------------------------------------------------------------------
 * Purpose: set the enabled flag of a peer group
 * Input:	the peer group's ID and the enabled flag
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int setPeerGroupEnabledFlag( int peerGroupID, int enabledFlag )
{
	// check the peer group ID is valid
	if( peerGroupID >= MAX_PEER_GROUP_IDS )
	{
		log_err("setPeerGroupEnabledFlag: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("setPeerGroupEnabledFlag: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// check if enabled flag changes
	if( PeerGroups[peerGroupID]->configuration->enabled == enabledFlag )
		return 0;

	// if changed ...
	log_msg("setPeerGroupEnabledFlag: from %d to %d", PeerGroups[peerGroupID]->configuration->enabled, enabledFlag);
	PeerGroups[peerGroupID]->configuration->enabled = enabledFlag;
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: delete a peer group
 * Input:	the peer group's ID
 * Output: 0 means success, -1 means failure
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int
deletePeerGroup(int peerGroupID)
{
	// check the peer group ID is valid
	if( peerGroupID >= MAX_PEER_GROUP_IDS )
	{
		log_err("deletePeerGroup: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("deletePeerGroup: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	int i;
	for( i=0; i<PeerGroups[peerGroupID]->configuration->numOfAnnCaps; i++ )
	{
		if( PeerGroups[peerGroupID]->configuration->announceCaps[i] != NULL )
			free( PeerGroups[peerGroupID]->configuration->announceCaps[i] );
	}
	free( PeerGroups[peerGroupID]->configuration);
	PPeerGroup tmp = PeerGroups[peerGroupID];
	PeerGroups[peerGroupID] = NULL;
	free( tmp );
	return 0;
}

/*--------------------------------------------------------------------------------------
 * Purpose: add an annouce capabilty to a peer group, called by CLI
 * Input:	the peer group's ID, cap code, cap value len and cap value.
 * Output: 0 means ok. -1 means failure because the capabilty already exists
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int peerGroupAddAnnounceCapability(int peerGroupID, int code, int len, u_char *value)
{
	// check the peer group ID is valid
	if( peerGroupID >= MAX_PEER_GROUP_IDS )
	{
		log_err("peerAddAnnounceCapability: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("peerAddAnnounceCapability: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	return addAnnounceCapability(PeerGroups[peerGroupID]->configuration, code, len, value);
}

/*--------------------------------------------------------------------------------------
 * Purpose: remove an annouce capabilty from a peer group, called by CLI
 * Input:	the peer group's ID, cap code, cap value len and cap value.
 * Output: 0 means ok. -1 mean failure because the capabilty already exists
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int peerGroupRemoveAnnounceCapability(int peerGroupID, int code, int len, u_char *value)
{
	// check the peer group ID is valid
	if( peerGroupID >= MAX_PEER_GROUP_IDS )
	{
		log_err("peerRemoveAnnounceCapability: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("peerRemoveAnnounceCapability: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	return removeAnnounceCapability(PeerGroups[peerGroupID]->configuration, code, len, value);
}

/*--------------------------------------------------------------------------------------
 * Purpose: add an receive capabilty to a peer group, called by CLI
 * Input:	the peer group's ID, action, cap code, cap value len and cap value.
 * Output: 0 means ok. -1 means failure because the capabilty already exists
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int peerGroupAddReceiveCapability(int peerGroupID, int action, int code, int len, u_char *value)
{
	// check the peer group ID is valid
	if( peerGroupID >= MAX_PEER_GROUP_IDS )
	{
		log_err("peerGroupAddReceiveCapability: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("peerGroupAddReceiveCapability: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	return addReceiveCapability(PeerGroups[peerGroupID]->configuration, action, code, len, value);
}

/*--------------------------------------------------------------------------------------
 * Purpose: remove a receive capabilty from a peer group, called by CLI
 * Input:	the peer group's ID, action, cap code, cap value len and cap value.
 * Output: 0 means ok. -1 means failure because the capabilty does't exist
 *
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int peerGroupRemoveReceiveCapability(int peerGroupID, int action, int code, int len, u_char *value)
{
	// check the peer group ID is valid
	if( peerGroupID >= MAX_PEER_GROUP_IDS )
	{
		log_err("peerGroupRemoveReceiveCapability: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("peerGroupRemoveReceiveCapability: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}
	return removeReceiveCapability(PeerGroups[peerGroupID]->configuration, action, code, len, value);
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get an array of rules how to check received capabilites,
 		    these rules are from the peer group and default peer group
 * Input: the peer group's ID and a pointer to the return array
 * Output: the length of the return array
 * Note: 1. The caller doesn't need to allocate memory.
 *	 2. The caller must free the array after using it.
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupReceiveCapabities(int peerGroupID, PeerCapabilityRequirement **rcvCaps)
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupReceiveCapabities: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupReceiveCapabities: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;
	}

	// first allocate memory for the peer's receive capabilites
	int len = 0;
	PeerCapabilityRequirement *caps = NULL;

	// put all the peer group receive capabilites in the list at first
	int i = 0;
	for(i = 0; i < PeerGroups[peerGroupID]->configuration->numOfReceiveCaps; i++)
	{
		PeerCapabilityRequirement tmp = PeerGroups[peerGroupID]->configuration->receiveCapRequirements[i];
		if( findReceiveCapabilityWithoutAction(len, caps, tmp.code, tmp.checkValueLen, tmp.checkValue) < 0 )
		{
			len++;
			caps = (PeerCapabilityRequirement *)realloc (caps, len * sizeof(PeerCapabilityRequirement));
			if (caps == NULL)
			{
				log_warning("getPeerGroupReceiveCapabities: Unable to allocate memory");
				return -1;
			}
			caps[len-1] = tmp;
		}
	}

	// then put all the receive capabilites from default peer group
	if(PeerGroups[peerGroupID]->configuration->groupID >= 0)
	{
		for(i = 0; i < PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->numOfReceiveCaps; i++)
		{
			PeerCapabilityRequirement tmp = PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->receiveCapRequirements[i];
			if( findReceiveCapabilityWithoutAction(len, caps, tmp.code, tmp.checkValueLen, tmp.checkValue) < 0 )
			{
				len++;
				caps = (PeerCapabilityRequirement *) realloc (caps, len * sizeof(PeerCapabilityRequirement));
				if (caps == NULL)
				{
					log_warning("getPeerGroupReceiveCapabities: Unable to allocate memory");
					return -1;
				}
				caps[len-1] = tmp;
			}
		}
	}

#ifdef DEBUG
	for(i = 0; i < len; i++)
	{
		debug(__FUNCTION__, "Peer Group %d: Capability Code %d, len %d, action %d", peerGroupID, caps[i].code, caps[i].checkValueLen, caps[i].action);
	}
#endif

	*rcvCaps = caps;
	return len;
}

/*--------------------------------------------------------------------------------------
 * Purpose: Get an array of announced capabilities which are from the peer group and default group
 * Input: the peer group's ID and a pointer to the return array
 * Output: the length of the return array
 * Note: 1. The caller doesn't need to allocate memory.
 *	 2. The caller must free the array after using it.
 * He Yan @ Sep 22, 2008
 * -------------------------------------------------------------------------------------*/
int getPeerGroupAnnounceCapabities(int peerGroupID, PBgpCapability **annCaps)
{
	// check the peer group ID is valid
	if (peerGroupID >= MAX_PEER_GROUP_IDS)
	{
		log_err("getPeerGroupAnnounceCapabities: peer group ID %d exceeds max %d", peerGroupID, MAX_PEER_GROUP_IDS);
		return -1;
	}
	// check if the peer group is configured
	if( PeerGroups[peerGroupID] == NULL )
	{
		log_err("getPeerGroupAnnounceCapabities: couldn't find a peer group with ID:%d", peerGroupID);
		return -1;	}

	int len = 0;
	PBgpCapability *caps = NULL;

	// put all the peer group's announce capabilites in the list at first
	int i = 0;
	for(i = 0; i < PeerGroups[peerGroupID]->configuration->numOfAnnCaps; i++)
	{
		PBgpCapability tmp = PeerGroups[peerGroupID]->configuration->announceCaps[i];
		if( findAnnounceCapabilityInArray(len, caps, tmp->code, tmp->length, tmp->value) < 0 )
		{
			len++;
			caps = (PBgpCapability *)realloc (caps, len * sizeof(PBgpCapability));
			if (caps == NULL)
			{
				log_warning("getPeerAnnounceCapabities: Unable to allocate memory");
				return -1;
			}
			caps[len-1] = createGenericBGPCapability( tmp->code, tmp->length, tmp->value);
		}
	}

	// then put all the receive capabilites from default peer group
	if(PeerGroups[peerGroupID]->configuration->groupID >= 0)
	{
		for(i = 0; i < PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->numOfAnnCaps; i++)
		{
			PBgpCapability tmp = PeerGroups[PeerGroups[peerGroupID]->configuration->groupID]->configuration->announceCaps[i];
			if( findAnnounceCapabilityInArray(len, caps, tmp->code, tmp->length, tmp->value) < 0 )
			{
				len++;
				caps = (PBgpCapability *) realloc (caps, len * sizeof(PBgpCapability));
				if (caps == NULL)
				{
					log_warning("getPeerAnnounceCapabities: Unable to allocate memory");
					return -1;
				}
				caps[len-1] = createGenericBGPCapability( tmp->code, tmp->length, tmp->value);
			}
		}
	}

#ifdef DEBUG
	for(i = 0; i < len; i++)
	{
		debug(__FUNCTION__, "Peer Group %d: Annouce Capability Code %d, len %d", peerGroupID, caps[i]->code, caps[i]->length);
	}
#endif
	*annCaps = caps;
	return len;
}


text:
package io.swagger.api;

import io.swagger.model.Pet;

import io.swagger.annotations.*;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

import javax.validation.constraints.*;
@javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2017-03-07T09:20:41.226Z")

@Controller
public class DefaultApiController implements DefaultApi {

    public ResponseEntity<List<Pet>> rootGet( @Min(11) @Max(10000) @ApiParam(value = "number of pets to return", defaultValue = "11") @RequestParam(value = "limit", required = false, defaultValue="11") Integer limit) {
        // do some magic!
        return new ResponseEntity<List<Pet>>(HttpStatus.OK);
    }

    public ResponseEntity<Void> rootPost(@ApiParam(value = "The pet JSON you want to post" ,required=true ) @RequestBody Pet pet) {
        // do some magic!
        return new ResponseEntity<Void>(HttpStatus.OK);
    }

    public ResponseEntity<Void> rootPut(@ApiParam(value = "The pet JSON you want to post" ,required=true ) @RequestBody Pet pet) {
        // do some magic!
        return new ResponseEntity<Void>(HttpStatus.OK);
    }

}

redpajama_set_name: RedPajamaGithub


text:
/**
 * Created with JetBrains PhpStorm.
 * User: Michael Yegorov
 * Date: 7/11/12
 * Time: 2:43 PM
 * To change this template use File | Settings | File Templates.
 */

//todo - вынести отсюда функции работы с основной системой (сделать отдельный класс, или придумать куда распихать)

Funcs = function () {};

Funcs.prototype = {

	// функция ошибки сеттера для финальных свойств
	setterError:function () {
		throw('trying to overwrite final property');
	},

	// запись в консоль
	log:function (text) {

		if (tinng.cfg['logging']) {
			var date = new Date(), time;

			if (date.toLocaleFormat) {
				time = date.toLocaleFormat('%H:%M:%S');
			} else {
				var temp = {};
				temp.H = date.getHours();
				temp.M = date.getMinutes();
				temp.S = date.getSeconds();
				for (var i in temp) {
					if (temp[i] * 1 < 10) temp[i] = '0' + temp[i];
				}
				time = temp.H + ':' + temp.M + ':' + temp.S;
			}
			console.info(time + ' - ' + text);
		}
	},

	// обработчик таймаута
	advClearTimeout:function (timeout) {
		if (timeout) {
			this.log('timeout found: ' + timeout + '. cleared');
			clearTimeout(timeout);
		}
		return false;
	},

	// оздать таймстамп из строки с SQL
	sql2stamp:function (str) {
		if (!str) return false;
		var str1 = str.split(' ');
		var dates = str1[0].split('-');
		var times = str1[1].split(':');
		return new Date(dates[0], dates[1] - 1, dates[2], times[0], times[1], times[2]).getTime();
	},

	phpts2date:function(str) {
		var jsts = parseInt(str, 10) * 1000;
		return new Date(jsts);
	},

	stopProp:function (e) {
		e.stopPropagation();
//		var e = e || window.event;
//		e.stopPropagation ? e.stopPropagation() : (e.cancelBubble=true);
	},

	bind:function (context, funcNames) {
		/*
		 *  если funcNames:
		 * 	строка - указанная функция привязывается к контексту класса по ее имени
		 * 	массив строк - все функции, перечисленные по именам, привязываются к контексту класса
		 *	не подан - все функции прототипа класса привязываются к контексту класса
		 * */

		// собственно, функция привязки к контексту
		var _bind = function (funcName) {
			if (typeof context[funcName] == 'function') context[funcName] = context[funcName].bind(context);
		}

		switch (typeof funcNames) {
			// второй аргумент вообще не подан - привязываем все функции
			case 'undefined':

				for (var memberName in context) {
					// привязываем только функции НЕ начинающиеся с _ - эти функции будут с собственным this
					if (typeof context[memberName] == 'function' && memberName.indexOf('_') != 0) _bind(memberName);
				}

				break;
			// подан массив - привязываем все его элементы к контексту
			case 'object':

				for (var i = 0; i < funcNames.length; i++) _bind(funcNames[i]);

				break;
			// подана строка - привязываем одну функцию
			case 'string':
			default:

				_bind(funcNames);
		}
	},

	setCookie:function (config) {
		if (typeof config.name == 'undefined' || typeof config.value == 'undefined') return false;
		var str = config.name + '=' + encodeURIComponent(config.value);

		if (config.expires) str += '; expires=' + config.expires.toGMTString();

		//if (config.path)	str += '; path=' + config.path;
		// Всегда устанавливать куки в корень домена
		str += '; path=/';

		if (config.domain)  str += '; domain=' + config.domain;
		if (config.secure)  str += '; secure';

		document.cookie = str;
		return true;
	},

	getCookie:function (name) {
		var pattern = "(?:; )?" + name + "=([^;]*);?";
		var regexp = new RegExp(pattern);

		if (regexp.test(document.cookie))
			return decodeURIComponent(RegExp["$1"]);

		return false;
	},

	deleteCookie:function (config) {

		var newConfig = {
			name: (typeof config == 'string') ? config : config.name,
			value:'',
			expires:new Date(0)
		};

		if (typeof config == 'object'){
			if (typeof config.path != 'undefined') newConfig.path = config.path;
			if (typeof config.domain != 'undefined') newConfig.domain = config.domain;
		}

		this.setCookie(newConfig);
		return true;
	},

	objectConfig:function(argSettings, defaultSettings) {
		var settings = {};
		for (var key in defaultSettings) {
			//if (typeof debug_1 != 'undefined')  console.log(key, argSettings[key], defaultSettings[key])
			settings[key] = (typeof argSettings[key] != 'undefined') ? argSettings[key] : defaultSettings[key];
		}

		return settings;
	},

	stopPropagation:function(e){
		e.stopPropagation();
	},

	isEmptyObject:function(object){
		for (var key in object) {
			if (object.propertyIsEnumerable(key)) return false;
		}
		return true;
	},

	objectSize:function(object){
		var i = 0

		for (var key in object) {
			if (object.propertyIsEnumerable(key)) i++;
		}
		return i;
	},

	getSortIndex:function(array, newValue, sortField, sortOrder, watchDirection){
		if (typeof sortOrder == 'undefined') sortOrder = 'asc';

		// from which end of array will we look for matching value. Does not affect result, but affects performance on long arrays
		if (typeof watchDirection == 'undefined') watchDirection = 'asc';

		if (watchDirection == 'asc') {

			for (var i = 0; i < array.length; i++) {
				var item = array[i];

				if (sortOrder == 'asc' && newValue[sortField] < item[sortField]) break;
				if (sortOrder == 'desc' && newValue[sortField] >= item[sortField]) break;
			}

		} else {

			var i = array.length;
			while(i--){
				var item = array[i];

				if (sortOrder == 'asc' && newValue[sortField] >= item[sortField]) break;
				if (sortOrder == 'desc' && newValue[sortField] < item[sortField]) break;
			}

			i++;
		}

		return i;
	}
}

tinng.funcs = new Funcs();


text:
package com.bencvt.minecraft.buildregion.ui.window;

import java.awt.Desktop;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

import libshapedraw.primitive.Color;
import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiSlot;
import net.minecraft.src.Tessellator;

import com.bencvt.minecraft.buildregion.Controller;

/**
 * The help screen, which is just a scrollable text area.
 *
 * @author bencvt
 */
public class GuiScreenHelp extends GuiScreenBase {
    public static final int MARGIN_X = 48;
    public static final int TEXT_ARGB = Color.WHITE.getARGB();
    public static final URI WEBSITE_URL = URI.create("http://bit.ly/BuildRegion");

    private final GuiStandardButton buttonDone = new GuiStandardButton(this, i18n("button.done"));
    private final ArrayList<String> lines = new ArrayList<String>();
    private final HashMap<Integer, String> rightColumnLines = new HashMap<Integer, String>();
    private final Controller controller;
    private int urlLineNum;
    private int leftColumnWidth;
    private GuiSlot contents;

    public GuiScreenHelp(GuiScreenBase parentScreen, Controller controller) {
        super(parentScreen);
        this.controller = controller;
    }

    private void getLines(Controller controller) {
        lines.clear();
        lines.addAll(fontRenderer.listFormattedStringToWidth(i18n("help.about"), width - MARGIN_X*2));
        lines.add("");
        lines.add(i18n("help.author") + " bencvt");
        urlLineNum = lines.size();
        lines.add(i18n("help.url") + " \u00a79\u00a7n" + WEBSITE_URL);
        lines.add(i18n("help.usage"));
        lines.addAll(Arrays.asList(controller.getInputManager().getUsage("  ").split("\n")));
        lines.add("");
        lines.addAll(fontRenderer.listFormattedStringToWidth(i18n("help.gui"), width - MARGIN_X*2));
        lines.add("");

        rightColumnLines.clear();
        leftColumnWidth = 0;
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            int t = line.indexOf('\t');
            if (t >= 0) {
                String leftColumn = line.substring(0, t);
                leftColumnWidth = Math.max(leftColumnWidth, fontRenderer.getStringWidth(leftColumn));
                lines.set(i, leftColumn);
                rightColumnLines.put(i, line.substring(t + 1));
            }
        }
    }

    @Override
    public void initGui() {
        getLines(controller);

        buttonDone.setWidth(200).setPositionXY((width - buttonDone.getWidth())/2, height - 30);
        controlList.add(buttonDone);

        contents = new GuiSlot(mc, width, height, 16, height - 28, fontRenderer.FONT_HEIGHT + 1) {
            private boolean openedUrl;

            @Override
            protected int getSize() {
                return lines.size();
            }

            @Override
            protected void elementClicked(int slotNum, boolean doubleClick) {
                if (slotNum == urlLineNum && !openedUrl) {
                    try {
                        Desktop.getDesktop().browse(WEBSITE_URL);
                    } catch (Throwable t) {
                        // do nothing
                    }
                    openedUrl = true;
                }
            }

            @Override
            protected boolean isSelected(int slotNum) {
                return false;
            }

            @Override
            protected void drawBackground() {
                // do nothing
            }

            @Override
            protected void drawSlot(int slotNum, int xPos, int yPos, int slotContentHeight, Tessellator tess) {
                getFontRenderer().drawString(lines.get(slotNum), MARGIN_X, yPos, TEXT_ARGB);
                if (rightColumnLines.containsKey(slotNum)) {
                    getFontRenderer().drawString(rightColumnLines.get(slotNum),
                            leftColumnWidth + MARGIN_X + 8, yPos, TEXT_ARGB);
                }
            }

            /**
             * This method is defined only by Forge, allowing mods to make a
             * custom background for each slot. By overriding it with an empty
             * method, the original background remains -- in our case, a
             * nice darkened view of the game world.
             * <p>
             * This method will never be called if we're using ModLoader
             * instead, as vanilla Minecraft hard-codes slot backgrounds. So
             * our help screen will have an interesting background when using
             * Forge, and a plain black/dirt background when not.
             */
            protected void drawContainerBackground(Tessellator tess) {
                // do nothing
            }

            @Override
            protected int getScrollBarX() {
                return width - 10;
            }
        };
    }

    @Override
    public void drawScreen(int xMouse, int yMouse, float partialTick) {
        drawDefaultBackground();
        contents.drawScreen(xMouse, yMouse, partialTick);
        drawCenteredString(fontRenderer, controller.getModTitle(), width / 2, 4, TEXT_ARGB);
        super.drawScreen(xMouse, yMouse, partialTick);
    }

    @Override
    protected void actionPerformed(GuiButton guiButton) {
        if (guiButton == buttonDone) {
            close();
        }
    }
}


text:
package org.openhds.controller.util;

/*
 * Slightly modified version of the com.ibatis.common.jdbc.ScriptRunner class
 * from the iBATIS Apache project. Only removed dependency on Resource class
 * and a constructor
 */
/*
 *  Copyright 2004 Clinton Begin
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * Tool to run database scripts
 */
public class ScriptRunner {

	private static final String DEFAULT_DELIMITER = ";";

	private Connection connection;

	private boolean stopOnError;
	private boolean autoCommit;

	private PrintWriter logWriter = new PrintWriter(System.out);
	private PrintWriter errorLogWriter = new PrintWriter(System.err);

	private String delimiter = DEFAULT_DELIMITER;
	private boolean fullLineDelimiter = false;

	/**
	 * Default constructor
	 */
	public ScriptRunner(Connection connection, boolean autoCommit, boolean stopOnError) {
		this.connection = connection;
		this.autoCommit = autoCommit;
		this.stopOnError = stopOnError;
	}

	public void setDelimiter(String delimiter, boolean fullLineDelimiter) {
		this.delimiter = delimiter;
		this.fullLineDelimiter = fullLineDelimiter;
	}

	/**
	 * Setter for logWriter property
	 *
	 * @param logWriter
	 *            - the new value of the logWriter property
	 */
	public void setLogWriter(PrintWriter logWriter) {
		this.logWriter = logWriter;
	}

	/**
	 * Setter for errorLogWriter property
	 *
	 * @param errorLogWriter
	 *            - the new value of the errorLogWriter property
	 */
	public void setErrorLogWriter(PrintWriter errorLogWriter) {
		this.errorLogWriter = errorLogWriter;
	}

	/**
	 * Runs an SQL script (read in using the Reader parameter)
	 *
	 * @param reader
	 *            - the source of the script
	 */
	public void runScript(Reader reader) throws IOException, SQLException {
		try {
			boolean originalAutoCommit = connection.getAutoCommit();
			try {
				if (originalAutoCommit != this.autoCommit) {
					connection.setAutoCommit(this.autoCommit);
				}
				runScript(connection, reader);
			} finally {
				connection.setAutoCommit(originalAutoCommit);
			}
		} catch (IOException e) {
			throw e;
		} catch (SQLException e) {
			throw e;
		} catch (Exception e) {
			throw new RuntimeException("Error running script.  Cause: " + e, e);
		}
	}

	/**
	 * Runs an SQL script (read in using the Reader parameter) using the
	 * connection passed in
	 *
	 * @param conn
	 *            - the connection to use for the script
	 * @param reader
	 *            - the source of the script
	 * @throws SQLException
	 *             if any SQL errors occur
	 * @throws IOException
	 *             if there is an error reading from the Reader
	 */
	private void runScript(Connection conn, Reader reader) throws IOException,
			SQLException {
		StringBuffer command = null;
		try {
			LineNumberReader lineReader = new LineNumberReader(reader);
			String line = null;
			while ((line = lineReader.readLine()) != null) {
				if (command == null) {
					command = new StringBuffer();
				}
				String trimmedLine = line.trim();
				if (trimmedLine.startsWith("--")) {
					println(trimmedLine);
				} else if (trimmedLine.length() < 1
						|| trimmedLine.startsWith("//")) {
					// Do nothing
				} else if (trimmedLine.length() < 1
						|| trimmedLine.startsWith("--")) {
					// Do nothing
				} else if (!fullLineDelimiter
						&& trimmedLine.endsWith(getDelimiter())
						|| fullLineDelimiter
						&& trimmedLine.equals(getDelimiter())) {
					command.append(line.substring(0, line
							.lastIndexOf(getDelimiter())));
					command.append(" ");
					Statement statement = conn.createStatement();

					println(command);

					boolean hasResults = false;
					if (stopOnError) {
						hasResults = statement.execute(command.toString());
					} else {
						try {
							statement.execute(command.toString());
						} catch (SQLException e) {
							e.fillInStackTrace();
							printlnError("Error executing: " + command);
							printlnError(e);
						}
					}

					if (autoCommit && !conn.getAutoCommit()) {
						conn.commit();
					}

					ResultSet rs = statement.getResultSet();
					if (hasResults && rs != null) {
						ResultSetMetaData md = rs.getMetaData();
						int cols = md.getColumnCount();
						for (int i = 0; i < cols; i++) {
							String name = md.getColumnLabel(i);
							print(name + "\t");
						}
						println("");
						while (rs.next()) {
							for (int i = 0; i < cols; i++) {
								String value = rs.getString(i);
								print(value + "\t");
							}
							println("");
						}
					}

					command = null;
					try {
						statement.close();
					} catch (Exception e) {
						// Ignore to workaround a bug in Jakarta DBCP
					}
					Thread.yield();
				} else {
					command.append(line);
					command.append(" ");
				}
			}
			if (!autoCommit) {
				conn.commit();
			}
		} catch (SQLException e) {
			e.fillInStackTrace();
			printlnError("Error executing: " + command);
			printlnError(e);
			throw e;
		} catch (IOException e) {
			e.fillInStackTrace();
			printlnError("Error executing: " + command);
			printlnError(e);
			throw e;
		} finally {
			conn.rollback();
			flush();
		}
	}

	private String getDelimiter() {
		return delimiter;
	}

	private void print(Object o) {
		if (logWriter != null) {
			System.out.print(o);
		}
	}

	private void println(Object o) {
		if (logWriter != null) {
			logWriter.println(o);
		}
	}

	private void printlnError(Object o) {
		if (errorLogWriter != null) {
			errorLogWriter.println(o);
		}
	}

	private void flush() {
		if (logWriter != null) {
			logWriter.flush();
		}
		if (errorLogWriter != null) {
			errorLogWriter.flush();
		}
	}
}


text:
'use strict';

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    jshint: {
      all: [
        'Gruntfile.js',
        'tasks/*.js',
        '<%= nodeunit.tests %>'
      ],
      options: {
        jshintrc: '.jshintrc'
      }
    },

    // Before generating any new files, remove any previously-created files.
    clean: {
      tests: ['tmp']
    },

    // Configuration to be run (and then tested).
    underscoreTpl: {
      dev: {
        options: {
          extname: ['.tpl','.string']
        },
        src: 'test',
        dest: 'tmp'
      }
    },

    // Unit tests.
    nodeunit: {
      tests: ['test/*_test.js']
    }

  });

  // Actually load this plugin's task(s).
  grunt.loadTasks('tasks');

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-nodeunit');

  // Whenever the "test" task is run, first clean the "tmp" dir, then run this
  // plugin's task(s), then test the result.
  grunt.registerTask('test', ['clean', 'underscoreTpl_build', 'nodeunit']);

  // By default, lint and run all tests.
  grunt.registerTask('default', ['jshint', 'test']);
  grunt.registerTask('build', ['clean', 'underscoreTpl']);
};