package cdac.medinfo.sdk.hl7282.hl7net.Client;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import cdac.medinfo.sdk.hl7282.baselibs.messagedictionary.MessageMapReader;
import cdac.medinfo.sdk.hl7282.baselibs.messages.ACK;
import cdac.medinfo.sdk.hl7282.baselibs.messages.IMessageRecepient;
import cdac.medinfo.sdk.hl7282.baselibs.messages.IMessageSource;
import cdac.medinfo.sdk.hl7282.baselibs.messages.Message;
import cdac.medinfo.sdk.hl7282.baselibs.messages.MessageFactory;
import cdac.medinfo.sdk.hl7282.baselibs.parserserializer.HL7Serializer;
import cdac.medinfo.sdk.hl7282.baselibs.segments.BHS;
import cdac.medinfo.sdk.hl7282.baselibs.segments.BTS;
import cdac.medinfo.sdk.hl7282.baselibs.segments.FHS;
import cdac.medinfo.sdk.hl7282.baselibs.segments.FTS;
import cdac.medinfo.sdk.hl7282.baselibs.segments.MSA;
import cdac.medinfo.sdk.hl7282.baselibs.segments.MSH;
import cdac.medinfo.sdk.hl7282.commoninterface.ISegment;
import cdac.medinfo.sdk.hl7282.commoninterface.ISegmentSet;
import cdac.medinfo.sdk.hl7282.commoninterface.ISingleCollection;
import cdac.medinfo.sdk.hl7282.exceptions.InvalidMessageException;
import cdac.medinfo.sdk.hl7282.hl7model.messages.patientadministration.ADTRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.patientadministration.ADTSource;
import cdac.medinfo.sdk.hl7282.hl7model.messages.query.QryRecepient;
import cdac.medinfo.sdk.hl7282.hl7model.messages.query.QrySource;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.batch.BatchAgent;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.batch.HL7Batch;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.batch.HL7BatchFile;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.fragment.FragmentAgent;
import cdac.medinfo.sdk.hl7282.hl7net.auxiliaryprotocol.transactionhandler.TransactionHandler;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IBatchProcessor;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IFragmentProcessor;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IHL7Batch;
import cdac.medinfo.sdk.hl7282.hl7net.commons.IHL7BatchFile;
import cdac.medinfo.sdk.hl7282.hl7net.commons.ITransactionHandler;
import cdac.medinfo.sdk.hl7282.hl7net.localextension.Populate_Test;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.IBatchReceiver;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.IExceptionListener;
import cdac.medinfo.sdk.hl7282.hl7net.upperlayer.UserSession;
import cdac.medinfo.sdk.hl7282.utils.EnumMessageCode;
import cdac.medinfo.sdk.hl7282.utils.EnumMessageStructure;
import cdac.medinfo.sdk.hl7282.utils.HL7Config;
import cdac.medinfo.sdk.hl7282.utils.IMap;
import cdac.medinfo.sdk.hl7282.utils.IMessageMapReader;
import cdac.medinfo.sdk.hl7282.utils.SingleCollection;
import cdac.medinfo.sdk.hl7282.utils.StandardMethods;

/**
 * This sample code demonstrates implementation of Client of Patient Administration System
 * Client of Patient Administration System  has following capabilities
 * 1)Query other systems in network.
 * 2)Trigger event specific to the system (here Patient Administration).
 * 3)Send ACK in case of Reception of deferred response. 
 * 4)Send HL7 batch file to server.
 * 5)Send HL7 Batch to server.
 */
public class PatientAdminClient implements IExceptionListener,IBatchReceiver
{
	UserSession objUserSession = null;
	private int MsgControlID = 0;
	int i = 1;
	String strMsgControlID =null;
	Populate_Test objPopulateTest = null;

	public static void main(String[] args) 
	{
		try
		{
			/*
			 * Specifying logging directory.
			 * User can specify any directory where log files will be created.
			 * If no path is specified then logs will be generated in user's temp directory. 
			 */
			HL7Config.createInstance().enableLogging("E:\\Client_Logs");

			//Reading IP address for Patient Admin Server
			System.out.println("Enter IP Adderess of Patient Administration Server : ");
			InputStreamReader input = new InputStreamReader(System.in);
			BufferedReader reader = new BufferedReader(input);
			String strIP = reader.readLine();

			//Reading port for Patient Admin Server
			System.out.println("Enter Port on which Patient Administration Server is listening : ");
			String strPort = reader.readLine();
			int port = Integer.parseInt(strPort);

			//Initializing PatientAdminClient 
			PatientAdminClient objPatientAdminClient = new PatientAdminClient();
			objPatientAdminClient.initiate(strIP,port);
		}
		catch(Exception ioe)
		{
			ioe.printStackTrace();
		}
	}	

	/**
	 * Initiates this System as Patient Admin Client.
	 * Connects the Client to Server on specific IP Address & port on which Server System is listening.
	 * @param strIP  IP Address specified
	 * @param port port specified 
	 */
	public void initiate(String strIP,int port)
	{
		try 
		{
			objPopulateTest = new Populate_Test();
			
			//Creating user session for PatientAdminClient
			objUserSession  = new UserSession();

			MessageFactory objMessageFactory = MessageFactory.createInstance();


			/*   Patient Administration System */
			/*
			 * Instantiating Message Recipient for HL7System
			 * User can provide his own implementation of Message Recipient by implementing IMessageReceipient interface. 
			 */
			IMessageRecepient objADTRecepient = new ADTRecepient();

			/*
			 * Adding Patient Admin Recipient on Message Factory.
			 * By setting this recipient client becomes capable to create messages and send Events of Patient Admin System
			 * Similarly user can set recipients for different systems.
			 * sdk for HL7 provides sources for all systems specified by HL7.
			 */ 
			objMessageFactory.addMessageRecepient(objADTRecepient);

			/*
			 * Instantiating Message Source for HL7System
			 * User can provide his own implementation of Message Source by implementing IMessageSource interface. 
			 */
			IMessageSource objADTSource  = new ADTSource();

			/*
			 * Adding Patient Admin Source and Recipient on Message Factory.
			 * By setting this source client becomes capable to create messages and receive responses of Patient Admin System
			 * Similarly user can set sources for different systems.
			 * sdk for HL7 provides sources for all systems specified by HL7.
			 */ 
			objMessageFactory.addMessageSource(objADTSource);


			/*   Query System */
			//Initiating Message Recipient for Query System.
			IMessageRecepient objQryRecepient = new QryRecepient();

			//Add the Message Recipient in MessageFactory.
			objMessageFactory.addMessageRecepient(objQryRecepient);

			//Initiating Message Source for Query System.
			IMessageSource objQrySource  = new QrySource();

			//Add MessageRecipient to MessageFactory.
			objMessageFactory.addMessageSource(objQrySource);

			/*
			 * Instantiating IFragmentProcessor which handles the fragmentation and defragmention for larger messages.
			 * FragmentAgent is the default implementation provided by sdk for HL7.
			 * User can provide his own implementation for FragmentProcessor by implementing IFragmentProcessor interface.
			 */ 
			IFragmentProcessor objIFragmentProcessor = new FragmentAgent();

			//Setting Fragment processor on user session.
			objUserSession.setFragmentProcessor(objIFragmentProcessor);
			
			//Enable MLLP on User Session.
			objUserSession.enableMLLP();

			/*
			 * Instantiating IBatchProcessor which handles HL7Batch and HL7BatchFiles.
			 * BatchAgent is the default implementation provided by SDK for HL7.
			 * User can provide his own implementation for BatchProcessor by implementing IBatchProcessor interface.
			 */
			IBatchProcessor objIBatchProcessor = new BatchAgent();

			//Setting Batch Processor on user session
			objUserSession.setBatchProcessor(objIBatchProcessor);

			/*
			 * Instantiating TransactionHandler which keeps track for the sending and receiving message 
			 * and does verification of each message during transaction.
			 * User can provide his own implementation for ClientSideTransactionHandler by implementing ITransactionHandler interface.
			 * if user wants verification for each message within transaction then user has to set it else not.
			 */
			ITransactionHandler objClientSideTransactionHandler = new TransactionHandler();

			//Setting this transaction handler on User session.
			objUserSession.setClientSideTransactionHandler(objClientSideTransactionHandler);

			/*
			 * Setting the class implementing behavior of HL7System as listener in asynchronous mode,
			 * to process deferred queries.
			 * User can provide his own implementation by implementing interface IAsynReceiver
			 */
			objUserSession.addExceptionListener(this);

			//Set the reading and writing max length for this client which will be used to decide whether to fragment or not.
			objUserSession.setReadWriteLength(1024,1024);

			//Sets the wait period for which each User Session should wait till it 
			//receives ACK/response for triggered event/Query.
			//if user not sets then by default set to 20 sec.
			objUserSession.setWaitPeriod(6000);

			//Setting time period for which User Session will read on socket 
			//for given time period in milliseconds. 
			//The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout. 
			objUserSession.setTimeOut(0);

			//This will register the IBatchReceiver on user session.
			objUserSession.setIBatchReceiver(this);

			//Setting messageFactory on user session.
			objUserSession.setMessageFactory(objMessageFactory);

			//Connecting this client with PatientAdminServer
			objUserSession.connect(strIP, port);

			String strFilePath = null;
			boolean bContinue = true;

			/*
			 * loop for getting choice from user, and accordingly doing operations.
			 */
			while(bContinue)
			{
				InputStreamReader input = new InputStreamReader(System.in);
				BufferedReader reader = new BufferedReader(input);
				int iChoice = getChoice();
				if(iChoice>=1 && iChoice<=6)
				{
					System.out.print("\n\n\nEnter File To Send :");
					try
					{
						strFilePath = reader.readLine();
						onChoice(iChoice, strFilePath);
					}
					catch(IOException ioe)
					{
						ioe.printStackTrace();
					}
					System.out.println("Do you want to continue..(Y/N)");
					char ch = (char)reader.read();
					if(ch=='y' || ch=='Y')
						bContinue = true;
					else if(ch=='n' || ch=='N')
						bContinue = false;
					else
					{
						System.out.println("Invalid Choice...");
					}
				}
				else
				{
					System.out.println("Invalid Choice...");
				}
			}
			System.out.println("Ending Client..");
			objUserSession.close();

		}
		catch (Exception e)
		{
			System.out.println("Error Ocured (Ending Client..)== > "+e.getMessage());
			e.printStackTrace();
		}
	}

	/**
	 * This method is invoked when deferred response is received.
	 */
	public void onResponseReceive(Message deferredResponse)
	{

		System.out.println("Deferred Response Received............ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");

		String strFilePath = null;
		try
		{
			strFilePath = "E:\\Server" + i++ + ".hl7"; //reader.readLine();

			HL7Serializer objHL7Serializer = new HL7Serializer();
			objHL7Serializer.serialize(deferredResponse.getSegmentSet(), strFilePath);

			System.out.print("Message serialized successfully\n");

			//After receiving deferredResponse user sends Acknowledgment in response to Deferred response.
			//generate Acknowledgment with respect to deferred response.
			ACK ackMessage = generateAcknowledgement(deferredResponse);

			//Send Acknowledgment for deferred response
			objUserSession.sendMessage(ackMessage);

			synchronized (this) 
			{
				notify();	
			}
		}catch(IOException ioe)
		{
			ioe.printStackTrace();
		}
		catch (InvalidMessageException e) 
		{
			e.printStackTrace();
		} 
	}

	/**
	 * This method simulates user action to generate Acknowledgment from message received.
	 * This method is demonstrated for test purpose only.
	 * In the actual scenario,it is the responsibility of user to generates acknowledgment & sends it on remote end. 
	 * @param objReceivedMessage specified Message object
	 * @return ACK message object
	 */
	public ACK generateAcknowledgement(Message objReceivedMessage)
	{
		strMsgControlID = "MSG58"+MsgControlID++;
		
		IMessageMapReader objMessageMapReader = MessageMapReader.createInstance();
		IMap objMessageMap = objMessageMapReader.getMessageMap(EnumMessageCode.ACK, null);

		ACK ackMessage = new ACK(StandardMethods.getEnumTriggerEvent(objReceivedMessage.getTriggerEvent()), objMessageMap);
		MSH objMSH = objPopulateTest.populateMSH();
		objMSH.setMessageType(EnumMessageCode.ACK.getValue(), objReceivedMessage.getTriggerEvent(),EnumMessageStructure.ACK.getValue());
		objMSH.setMessageControlID(strMsgControlID);
		ackMessage.setHeader(objMSH);
		
		//MSA Segment
		MSA objMSA = new MSA();
		objMSA.setAcknowledgmentCode("AA");
		objMSA.setMessageControlID(objReceivedMessage.getHeader().getMessageControlID().getValue().toString());
		objMSA.setExpectedSequenceNumber("1234567");
		ackMessage.setMessageAcknowledgmentSegment(objMSA);
		return ackMessage;
	}

	/**
	 * This method simulates user action to generate Acknowledgment from message received in the batch.
	 * This method is demonstrated for test purpose only.
	 * In the actual scenario,it is the responsibility of user to generates acknowledgment & sends it on remote end. 
	 * @param objMessageCollection specified Message collection from 
	 * @return objACKCollection - collection of ACK messages.
	 */
	public ISingleCollection<Message> generateAcknowledgement(ISingleCollection<Message> objMessageCollection)
	{
		ISingleCollection<Message> objACKCollection = new SingleCollection<Message>();
		for(Message objMessage :objMessageCollection)
		{
			objACKCollection.add(generateAcknowledgement(objMessage));
		}
		return objACKCollection;
	}


	private void acknowledgeResponseBatch(IHL7Batch objHL7Batch)
	{
		System.out.println("Deferred Response Received is Batch............ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
		try 
		{

			//After receiving deferredResponse user sends Acknowledgment in response to Deferred response.
			//generate Acknowledgment with respect to deferred response.

			BHS objBatchHeader  = new BHS();
			objBatchHeader.setBatchFieldSeparator('|');
			objBatchHeader.setBatchEncodingChars('^','&','~','\\','#');
			objBatchHeader.setBatchControlID(objHL7Batch.getBatchControlID());//Generate it using UUID jar.

			ISingleCollection<Message> objMessageCollection = generateAcknowledgement(objHL7Batch.getMessageCollection());

			int iMessageCount = 0;
			if(objMessageCollection != null )
				iMessageCount = objMessageCollection.size();

			BTS objBatchTrailer = new BTS();
			objBatchTrailer.addBatchTotals(""+iMessageCount);

			IHL7Batch objBatch = new HL7Batch(objBatchHeader,objBatchTrailer,objMessageCollection);

			ISingleCollection<IHL7Batch> objIHL7BatchCollection = new SingleCollection<IHL7Batch>();
			objIHL7BatchCollection.add(objBatch);

			FHS objBatchFileHeader  = new FHS();
			objBatchFileHeader.setFieldSeparator('|');
			objBatchFileHeader.setEncodingChars('^','&','~','\\','#');
			objBatchFileHeader.setFileControlID(StandardMethods.generateUUID());

			FTS objBatchFileTrailer = new FTS();
			objBatchFileTrailer.setFileBatchCount("1");

			IHL7BatchFile objBatchFile = new HL7BatchFile(objBatchFileHeader,objBatchFileTrailer,objIHL7BatchCollection);

			//Send Acknowledgment for deferred response
			System.out.println("Sending ACK for Deferred Response Batch..");

			objUserSession.sendBatchFile(objBatchFile);

			System.out.println("ACK for Deferred Response Batch is Sent ..");
			synchronized (this) 
			{
				notify();	
			}
		}
		catch (InvalidMessageException e) 
		{
			e.printStackTrace();
		}
		catch (IOException e) 
		{
			e.printStackTrace();
		}
	}

	/**
	 * This method is invoked when deferred response received is in Batch.
	 */
	public void onBatchReceive(IHL7BatchFile objBatchFile) 
	{
		ISingleCollection<IHL7Batch> objBatchCollection = objBatchFile.getHL7BatchCollection();
		for(IHL7Batch objBatch : objBatchCollection)
		{
			if(objBatch.isResponseBatch()  && objBatch.isDeferred())
			{
				acknowledgeResponseBatch(objBatch);
			}
			else
				System.out.println("ACK received for BatchID  " + objBatch.getBatchControlID());
		}
	}

	/**
	 * Get choice from user.
	 * @return
	 */
	private int getChoice()
	{
		System.out.println("Enter your choice to send PatientAdministration Messages:   ");
		System.out.println("1. Simple ADT Event Parsed from File");

		System.out.println("2. Simple Immediate Query Parsed from File");

		System.out.println("3. Simple Deferred Query Parsed from File");

		System.out.println("4. Simple Batch With Only ADT Events Parsed from File");
		
		System.out.println("5. Mixed Batch With ADT Events and Query Parsed from File");

		System.out.println("6. Batch File With only ADT Batches Parsed from File");

		InputStreamReader input = new InputStreamReader(System.in);
		BufferedReader reader = new BufferedReader(input);
		String strChoice = null;
		try
		{
			strChoice = reader.readLine();
			return Integer.parseInt(strChoice);
		}
		catch(IOException ioe)
		{
			ioe.printStackTrace();
		}
		catch (NumberFormatException nfe) 
		{
			System.out.println(nfe.getMessage());
		}
		return 0;
	}

	/**
	 * performs the operations as par the choice of user.
	 * @param iChoice
	 * @param strFilePath
	 */
	private void onChoice(int iChoice,String strFilePath)
	{
		try
		{
			switch (iChoice) 
			{
			case 1:// Simple ADT Event
				/*
				 *	User can directly send message from file with sendMessage method .
				 *  The path that is entered from console is fed to sendMessage method. 
				 *  In sendMessage method provide path of file containing serialized message.   
				 */

				objUserSession.sendMessage(strFilePath);
				ISingleCollection<Message> ackCollection1 = objUserSession.getRecievedMessagesCollection("MSG0001");
				if (ackCollection1 != null)
				{
					for (Message objMessage : ackCollection1)
					{
						if (objMessage.getMessageStructure().equals(EnumMessageStructure.ACK.toString()))
						{
							ACK ackMessage1 = (ACK)objMessage;
							System.out.println("ACK Received for event :: " + ackMessage1.getTriggerEvent());
						}
					}
				}
				else
					System.out.println("ACK Collection is empty");
				break;

			case 2: // Simple Immediate Query
				objUserSession.sendMessage(strFilePath);
				/*
				 * User retrieves response from usersession object in following manner.
				 */
				ISingleCollection<Message> responseCollection = objUserSession.getRecievedMessagesCollection("MSG0032");
				if (responseCollection != null)
				{
					if(responseCollection.size() != 0)
					{
						for (Message response :responseCollection)
						{
							if(!response.getMessageStructure().equals(EnumMessageStructure.ACK.getValue()))
							{
								System.out.println("Response Received :: " + response.getMessageStructure());
							}
						}
					}
					else
						System.out.println("Response Collection is empty");
				}
				else
					System.out.println("No response is recieved");
				break;

			case 3://Simple Deferred Query
				/*
				 * Send this deferred Query message.  
				 */
				objUserSession.sendMessage(strFilePath);

				/*
				 * In response server first sends Acknowledgment in response to deferred query.
				 * This can be received as demonstrated below. 
				 */
				ISingleCollection<Message> ackDeferredCollection = objUserSession.getRecievedMessagesCollection("MSG0003");
				if (ackDeferredCollection != null)
				{
					if(ackDeferredCollection.size() != 0)
					{
						for(Message objMessage :ackDeferredCollection)
						{
							if(objMessage.getMessageStructure().equals(EnumMessageStructure.ACK.getValue()))
							{
								ACK ackDefQueryMessage = (ACK)objMessage;
								System.out.println("ACK Received for Deffered Query :: " + ackDefQueryMessage.getTriggerEvent());
							}
						}
						/*
						 * To receive Deferred response User has to implement IAsyncReceiver
						 * Here this class implements IAsyncReceiver.
						 * The deferred response is received on onResponseReceive() method. 
						 */
						System.out.println("Total No of ACK received "+ ackDeferredCollection.size());
					}
					else
						System.out.println("ACK Collection is empty");
					
					Thread.sleep(9999);
					
					ISingleCollection<Message> responseCollection1 = objUserSession.getRecievedMessagesCollection("MSG0003");
					if (responseCollection1 != null)
					{
						if(responseCollection1.size() != 0)
						{
							for (Message response :responseCollection1)
							{
								if(!response.getMessageStructure().equals(EnumMessageStructure.ACK.getValue()))
								{
									System.out.println("Response Received :: " + response.getMessageStructure());
								}
							}
						}
						else
							System.out.println("Response Collection is empty");
					}
					else
						System.out.println("No response is recieved");
				}
				break;

			case 4:// Event Batch
			case 5:// Event and Query Batch
			{
				objUserSession.sendBatchFile(strFilePath);

				ISingleCollection<IHL7BatchFile> objACKBatchCollection = objUserSession.getResponseBatches();
				if (objACKBatchCollection != null)
				{
					for(IHL7BatchFile objIHL7BatchFile :objACKBatchCollection)
					{
						ISingleCollection<IHL7Batch> objIHL7Batch = objIHL7BatchFile.getHL7BatchCollection();
						for(IHL7Batch objBatch : objIHL7Batch)
						{
							System.out.println("ACK Received for Batch :: " + objBatch.getBatchControlID());
						}
					}
				}
				else
					System.out.println("ACK Collection is empty");
			}
			break;

			case 6:// BatchFile
				objUserSession.sendBatchFile(strFilePath);
				ISingleCollection<IHL7BatchFile> objACKBatchCollectionForFile = objUserSession.getResponseBatches();

				if(objACKBatchCollectionForFile != null)
				{
					for(IHL7BatchFile objBatchFromFile : objACKBatchCollectionForFile)
					{
						ISingleCollection<IHL7Batch> objhl7batch = objBatchFromFile.getHL7BatchCollection();

						for(IHL7Batch objIHL7Batch :objhl7batch)
						{
							System.out.println("ACK Received for Batch :: " + objIHL7Batch.getBatchControlID());
						}
					}
				}
				else
					System.out.println("ACK Collection is empty");
				break;

			default:
				break;
			}
		}
		catch (Exception e)
		{
			System.out.println("Error Ocured (Continue client) == > "+e.getMessage());
		}
	}

	/**
	 * This method is invoked when exception is fetched from remote end.
	 * @ex Exception fetched
	 * @buffer for which exception is received
	 */
	public void onException(Exception ex, byte[] buffer) 
	{
		System.out.println("In On Exception Receiced : Printing Stacktrace...");
		System.out.println(ex.getMessage());
		System.out.println("End of Stacktrace....");
		try
		{
			System.out.println("Byte Buffer is : ");
			ByteArrayOutputStream objByteArrayOutputStream = new ByteArrayOutputStream();
			objByteArrayOutputStream.write(buffer);

			objByteArrayOutputStream.writeTo(System.out);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * This method is invoked when exception is fetched from remote end.
	 * @ex Exception fetched
	 * @objISegmentSet for which Segment Set is Received.
	 */
	public void onException(Exception ex, ISegmentSet objISegmentSet)
	{
		System.out.println("In On Exception Receiced : Printing Stacktrace...");
		System.out.println(ex.getMessage());
		System.out.println("End of Stacktrace....");
		try
		{
			System.out.println("Segment Set is : ");
			ISingleCollection<ISegment> objISegmentSetCollection = objISegmentSet.getList();
			if(objISegmentSetCollection!=null)
			{
				System.out.println("Received Segment Set Contains following Segments:");
				for(ISegment objISegment : objISegmentSetCollection)
				{
					System.out.println(objISegment.getName());
				}
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

}
