Passing data between clients in a multithreaded server client program

Using TCP socket programming for multithreaded server client program,

Page 1 of 1

14 Replies - 16250 Views - Last Post: 01 December 2008 - 10:43 PM Rate Topic: -----

#1 always_learning  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 30-November 08

Passing data between clients in a multithreaded server client program

Posted 30 November 2008 - 06:02 PM

import java.io.*;
import java.net.*;




public class Server {
	
	public static int i = -1;		
	
	public static void main(String args[]) 
	{
		int port = 6789;
		Server server = new Server( port );
		server.startServer();
	}

	
	// declare a server socket and a client socket for the server;
	// declare the number of connections
	
   
	
	
	ServerSocket BidServer = null;
	Socket clientSocket = null;
	
	int port;
	
	public Server( int port ) {
	this.port = port;
	}

	public void stopServer() {
	System.out.println( "Server cleaning up." );
	System.exit(0);
	}

	public void startServer() {
	// Try to open a server socket on the given port
	// Note that we can't choose a port less than 1024 if we are not
	// privileged users (root)
	
	   try 
	   {
			 BidServer = new ServerSocket(port);
	   }
	   catch (IOException e) 
	   {
			 System.out.println(e);
	   }   
	
	System.out.println( "Server is started and is waiting for connections." );
	System.out.println( "With multi-threading, multiple connections are allowed." );
	System.out.println( "Any client can send -1 to stop the server." );

	// Whenever a connection is received, start a new thread to process the connection
	// and wait for the next connection.
	
	while ( true ) 
	{
		try 
		{
			 	clientSocket = BidServer.accept();
				i++;
				Server2Connection oneconnection = new Server2Connection(clientSocket, i, this);
				new Thread(oneconnection).start();
		}   
		catch (IOException e) 
		{
				System.out.println(e);
		}
	}
	}
}

class Server2Connection implements Runnable 
{	
	
	//String [] addr = new String [5];
	//Socket [] addr = new Socket [5];
	Socket [] addr = new Socket [5];
	PrintStream [] os = new PrintStream [5];
	BufferedReader [] is = new BufferedReader [5];
	
	int i;
	   
//	BufferedReader is;
   // PrintStream os;
	Socket clientSocket;
	//int id;
	Server server;
	
	public Server2Connection(Socket clientSocket, int i, Server server) 
	{
		
		this.clientSocket = clientSocket;
		//this.id = i;
		this.server = server;
		addr[i] = clientSocket;
		this.i=i;
		
		//System.out.println( "Connection " + id + " established with: " + clientSocket);
		//System.out.println( "Address : " + clientSocket.getInetAddress());
		//System.out.println( "Address with to string : " + clientSocket.getInetAddress().toString());
		//addclient(addr,clientsocket,i);
		//addr[i] = clientSocket;
		//i++;
		 
		
		try 
		{
			is[i] = new BufferedReader(new InputStreamReader(addr[i].getInputStream()));
			os[i] = new PrintStream(addr[i].getOutputStream());
			
		} 
		catch (IOException e) 
		{
			System.out.println(e);
		}
	}
	
   /*public void sendtoall(Socket [] addr,String line,PrintStream [] os,int i) //throws InterruptedException
	{
		int j=0;
		for(j=0;j<=i;j++)
		{
			//System.out.println("\n" + line + "received from client 1");
			System.out.println("Value of i in sendtoall " + i);
			os[j].println("\n" + line + "received from client 1");
			System.out.println("value of os [" + j + "] in sendtoall " + os[j]);
	//		  delay(50);
		}
		/*try
		{
		   wait(50);
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		} 
	}*/
	

   /* private void delay(int j) 
	{
			for(i=0;i<=j;i++);
	
	}*/

	public void run() 
	{
		//Socket clientSocket = null;
		String line;
		//int j=0;
		try 
		{
			boolean serverStop = false;

			while (true) 
			{
				
				line = is[i].readLine();
				System.out.println( "Received " + line + " from Connection " + i + "." );
				int n = Integer.parseInt(line);
				if ( n == -1 )
				{
					serverStop = true;
					break;
				}
				if ( n == 0 ) break;
			   /* for(i=0;i<=addr.length;i++)
				{
					 clientSocket = addr[i];
					//os = new PrintStream(clientSocket.getOutputStream());
				}*/
				   // System.out.println("Length = " + addr.length);
				//for(j=0;j<=1;j++)
				//{
					//if(i!=j)
					//{
						System.out.println("Value of i : " + i);
						System.out.println("Length of addr : " + addr.length);
						//os[i].println("" + n*n );
						
				//	}
						
			  // }
					//	sendtoall(addr,line,os,i);
						
						
						int j=0;
						for(j=0;j<=i;j++)
						{
							//System.out.println("\n" + line + "received from client 1");
							System.out.println("Value of i in sendtoall " + i);
							os[j].println("\n" + line + "received from client 1");
							System.out.println("value of os [" + j + "] in sendtoall " + os[j]);
					//		  delay(50);
						}
						
			}

			System.out.println( "Connection " + i + " closed." );
		   // is[i].close();
		   // os[i].close();
		   // clientSocket.close();

			if ( serverStop ) 
				server.stopServer();
		} 
		catch (IOException e)
		{
			System.out.println(e);
		}
	}
}






import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;

public class Client1 
{
	public static void main(String[] args) 
	{
		String hostname = "192.168.1.68";
		int port = 6789;

	// declaration section:
	// clientSocket: our client socket
	// os: output stream
	// is: input stream
	
		Socket clientSocket = null;  
		DataOutputStream os = null;
		BufferedReader is = null;
	
	// Initialization section:
	// Try to open a socket on the given port
	// Try to open input and output streams
	
		try 
		{
			clientSocket = new Socket(hostname, port);
			os = new DataOutputStream(clientSocket.getOutputStream());
			is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
		} 
		catch (UnknownHostException e) 
		{
			System.err.println("Don't know about host: " + hostname);
		} 
		catch (IOException e) 
		{
			System.err.println("Couldn't get I/O for the connection to: " + hostname);
		}
	
	// If everything has been initialized then we want to write some data
	// to the socket we have opened a connection to on the given port
	
		if (clientSocket == null || os == null || is == null) 
		{
			System.err.println( "Something is wrong. One variable is null." );
			return;
		}

		try 
		{
			while ( true ) 
			{
				System.out.print( "Enter an integer (0 to stop connection, -1 to stop server): " );
				BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
				String keyboardInput = br.readLine();
				os.writeBytes( keyboardInput + "\n" );

				int n = Integer.parseInt( keyboardInput );
				if ( n == 0 || n == -1 ) {
					break;
			}
		
			String responseLine = is.readLine();
			System.out.println("Server returns its square as: " + responseLine);
		}
		
		// clean up:
		// close the output stream
		// close the input stream
		// close the socket
		
		os.close();
		is.close();
		clientSocket.close();   
	  } 
	  catch (UnknownHostException e) 
	  {
		  System.err.println("Trying to connect to unknown host: " + e);
	  } 
	  catch (IOException e) 
	  {
		  System.err.println("IOException:  " + e);
	  }
   }		   
}




*Edited to add the correct [ /code] tags

This post has been edited by pbl: 30 November 2008 - 06:46 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Passing data between clients in a multithreaded server client program

#2 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8332
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Passing data between clients in a multithreaded server client program

Posted 30 November 2008 - 06:48 PM

And the question is ?
- code does not compile ?
- code generates a run-time error ?
- coe does not have the expected behaviour ?
Was This Post Helpful? 0
  • +
  • -

#3 always_learning  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 30-November 08

Re: Passing data between clients in a multithreaded server client program

Posted 30 November 2008 - 07:17 PM

View Postpbl, on 30 Nov, 2008 - 05:48 PM, said:

And the question is ?
- code does not compile ?
- code generates a run-time error ?
- coe does not have the expected behaviour ?


If I try to run to run the code for one client, it works but the reply to the client is delayed considerably. And for more than one clients , it generates a run time error at server showing the NullPointerException. I basically want to send the data received from one client to all the other clients , which needs some kind of synchronization and I am unable to implement it.
And Thanks for the reply .
Was This Post Helpful? 0
  • +
  • -

#4 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8332
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Passing data between clients in a multithreaded server client program

Posted 30 November 2008 - 07:35 PM

It is not that I want to preach for my parish but you make it over complicated for nothing

Here I have an as much as possible simple client/server connection example

http://www.dreaminco...snippet1917.htm

This post has been edited by pbl: 30 November 2008 - 08:07 PM

Was This Post Helpful? 0
  • +
  • -

#5 always_learning  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 30-November 08

Re: Passing data between clients in a multithreaded server client program

Posted 30 November 2008 - 07:43 PM

View Postpbl, on 30 Nov, 2008 - 06:35 PM, said:

It is not that I want to preach for my parish but you make it over complicated for nothing

Here I have an as much as possible client/server connection example

http://www.dreaminco...snippet1917.htm


Thank you so much for sending the simplified example of the client server program. But what should I do if I want to send the string received at the server from one client to all the other clients connected to the server.
Was This Post Helpful? 0
  • +
  • -

#6 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8332
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Passing data between clients in a multithreaded server client program

Posted 30 November 2008 - 08:14 PM

I would suggest to have, in you Server, side an array or an ArrayList of sockets
When you have a new connection request you add the new socket to that list
then you can scan that lisy and broacast the message
Was This Post Helpful? 0
  • +
  • -

#7 always_learning  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 30-November 08

Re: Passing data between clients in a multithreaded server client program

Posted 30 November 2008 - 08:21 PM

View Postpbl, on 30 Nov, 2008 - 07:14 PM, said:

I would suggest to have, in you Server, side an array or an ArrayList of sockets
When you have a new connection request you add the new socket to that list
then you can scan that lisy and broacast the message


I tried doing the same thing . I took an array of sockets , stored every new connection in it and then in the run() method I sent the message to all the addresses in that array . But it doesnt work.
Was This Post Helpful? 0
  • +
  • -

#8 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8332
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Passing data between clients in a multithreaded server client program

Posted 01 December 2008 - 06:20 PM

View Postalways_learning, on 30 Nov, 2008 - 07:21 PM, said:

View Postpbl, on 30 Nov, 2008 - 07:14 PM, said:

I would suggest to have, in you Server, side an array or an ArrayList of sockets
When you have a new connection request you add the new socket to that list
then you can scan that lisy and broacast the message


I tried doing the same thing . I took an array of sockets , stored every new connection in it and then in the run() method I sent the message to all the addresses in that array . But it doesnt work.


Are your clients listening in case a broadcast message arrives
Was This Post Helpful? 0
  • +
  • -

#9 always_learning  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 30-November 08

Re: Passing data between clients in a multithreaded server client program

Posted 01 December 2008 - 07:22 PM

View Postpbl, on 1 Dec, 2008 - 05:20 PM, said:

View Postalways_learning, on 30 Nov, 2008 - 07:21 PM, said:

View Postpbl, on 30 Nov, 2008 - 07:14 PM, said:

I would suggest to have, in you Server, side an array or an ArrayList of sockets
When you have a new connection request you add the new socket to that list
then you can scan that lisy and broacast the message


I tried doing the same thing . I took an array of sockets , stored every new connection in it and then in the run() method I sent the message to all the addresses in that array . But it doesnt work.


Are your clients listening in case a broadcast message arrives


Only first client receives the broadcasted message that too with delay. For eg : if the client1 sends 1 to the server , then the broadcasted message is not received. If now the client again sends say 2 , then it gets the previous broadcasted message like "1 received at client 1 " and this goes on. But in case of remaining clients , they dont receive anything ... they just dont get any message from the server .... at the same time the server receives the number sent by the other clients but also gets an error as :
Exception in thread "Thread-1" java.lang.NullPointerException
at Server2Connection.run(Server.java:202)
at java.lang.Thread.run(Unknown Source)
Was This Post Helpful? 0
  • +
  • -

#10 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8332
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Passing data between clients in a multithreaded server client program

Posted 01 December 2008 - 08:50 PM

Please repost your code
Was This Post Helpful? 0
  • +
  • -

#11 always_learning  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 30-November 08

Re: Passing data between clients in a multithreaded server client program

Posted 01 December 2008 - 09:16 PM

View Postpbl, on 1 Dec, 2008 - 07:50 PM, said:

Please repost your code


import java.io.*;
import java.net.*;

public class Server {
	
	public static int i = -1;		
	
	public static void main(String args[]) 
	{
		int port = 6789;
		Server server = new Server( port );
		server.startServer();
	}

	
	// declare a server socket and a client socket for the server;
	// declare the number of connections
	
   
	
	
	ServerSocket BidServer = null;
	Socket clientSocket = null;
	
	int port;
	
	public Server( int port ) {
	this.port = port;
	}

	public void stopServer() {
	System.out.println( "Server cleaning up." );
	System.exit(0);
	}

	public void startServer() {
	// Try to open a server socket on the given port
	// Note that we can't choose a port less than 1024 if we are not
	// privileged users (root)
	
	   try 
	   {
			 BidServer = new ServerSocket(port);
	   }
	   catch (IOException e) 
	   {
			 System.out.println(e);
	   }   
	
	System.out.println( "Server is started and is waiting for connections." );
	System.out.println( "With multi-threading, multiple connections are allowed." );
	System.out.println( "Any client can send -1 to stop the server." );

	// Whenever a connection is received, start a new thread to process the connection
	// and wait for the next connection.
	
	while ( true ) 
	{
		try 
		{
			 	clientSocket = BidServer.accept();
				i++;
				Server2Connection oneconnection = new Server2Connection(clientSocket, i, this);
				new Thread(oneconnection).start();
		}   
		catch (IOException e) 
		{
				System.out.println(e);
		}
	}
	}
}

class Server2Connection implements Runnable 
{	
	
	//String [] addr = new String [5];
	//Socket [] addr = new Socket [5];
	Socket [] addr = new Socket [5];
	PrintStream [] os = new PrintStream [5];
	BufferedReader [] is = new BufferedReader [5];
	
	int i;
	   
//	BufferedReader is;
   // PrintStream os;
	Socket clientSocket;
	//int id;
	Server server;
	
	public Server2Connection(Socket clientSocket, int i, Server server) 
	{
		
		

		this.clientSocket = clientSocket;
		//this.id = i;
		this.server = server;
		addr[i] = clientSocket;
		this.i=i;
		
		/*System.out.println( "Connection " + id + " established with: " + clientSocket);
		System.out.println( "Address : " + clientSocket.getInetAddress());
		System.out.println( "Address with to string : " + clientSocket.getInetAddress().toString());
		addclient(addr,clientsocket,i);
		addr[i] = clientSocket;
		i++;*/
		 
		
		try 
		{
			is[i] = new BufferedReader(new InputStreamReader(addr[i].getInputStream()));
			os[i] = new PrintStream(addr[i].getOutputStream());
			
		} 
		catch (IOException e) 
		{
			System.out.println(e);
		}
	}
	
   /*public void sendtoall(Socket [] addr,String line,PrintStream [] os,int i) //throws InterruptedException
	{
		int j=0;
		for(j=0;j<=i;j++)
		{
			System.out.println("\n" + line + "received from client 1");
			System.out.println("Value of i in sendtoall " + i);
			os[j].println("\n" + line + "received from client 1");
			System.out.println("value of os [" + j + "] in sendtoall " + os[j]);
			  delay(50);
		}
		try
		{
		   wait(50);
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		} 
	}
	

	private void delay(int j) 
	{
			for(i=0;i<=j;i++);
	
	}*/

	public void run() 
	{
		//Socket clientSocket = null;
		String line;
		//int j=0;
		try 
		{
			boolean serverStop = false;
			

			while (true) 
			{
				
				line = is[i].readLine();
				System.out.println( "Received " + line + " from Connection " + i + "." );
				int n = Integer.parseInt(line);
				if ( n == -1 )
				{
					serverStop = true;
					break;
				}
				if ( n == 0 ) break;
			   /* for(i=0;i<=addr.length;i++)
				{
					 clientSocket = addr[i];
					os = new PrintStream(clientSocket.getOutputStream());
				}
					System.out.println("Length = " + addr.length);
				for(j=0;j<=1;j++)
				{
					if(i!=j)
					{
						System.out.println("Value of i : " + i);
						System.out.println("Length of addr : " + addr.length);
						
		
					}
						
			   }
						sendtoall(addr,line,os,i);
						
						*/
				os[i].println("" + n*n );
						int j=0;
						for(j=0;j<=i;j++)
						{
							System.out.println("\n" + line + "received from client 1");
							System.out.println("Value of i in sendtoall " + i);
							os[j].println("\n" + line + "received from client 1");
							System.out.println("value of os [" + j + "] in sendtoall " + os[j]);
							// delay(50);
						}
						
			}

			System.out.println( "Connection " + i + " closed." );
			is[i].close();
			os[i].close();
			clientSocket.close();

			if ( serverStop ) 
				server.stopServer();
		} 
		catch (IOException e)
		{
			System.out.println(e);
		}
	}
}





import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;

public class Client1 
{
	public static void main(String[] args) 
	{
		String hostname = "192.168.1.68";
		int port = 6789;

	// declaration section:
	// clientSocket: our client socket
	// os: output stream
	// is: input stream
	
		Socket clientSocket = null;  
		DataOutputStream os = null;
		BufferedReader is = null;
	
	// Initialization section:
	// Try to open a socket on the given port
	// Try to open input and output streams
	
		try 
		{
			clientSocket = new Socket(hostname, port);
			os = new DataOutputStream(clientSocket.getOutputStream());
			is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
		} 
		catch (UnknownHostException e) 
		{
			System.err.println("Don't know about host: " + hostname);
		} 
		catch (IOException e) 
		{
			System.err.println("Couldn't get I/O for the connection to: " + hostname);
		}
	
	// If everything has been initialized then we want to write some data
	// to the socket we have opened a connection to on the given port
	
		if (clientSocket == null || os == null || is == null) 
		{
			System.err.println( "Something is wrong. One variable is null." );
			return;
		}

		try 
		{
			while ( true ) 
			{
				System.out.print( "Enter an integer (0 to stop connection, -1 to stop server): " );
				BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
				String keyboardInput = br.readLine();
				os.writeBytes( keyboardInput + "\n" );

				int n = Integer.parseInt( keyboardInput );
				if ( n == 0 || n == -1 ) {
					break;
			}
		
			String responseLine = is.readLine();
			System.out.println("Server returns its square as: " + responseLine);
		}
		
		// clean up:
		// close the output stream
		// close the input stream
		// close the socket
		
		os.close();
		is.close();
		clientSocket.close();   
	  } 
	  catch (UnknownHostException e) 
	  {
		  System.err.println("Trying to connect to unknown host: " + e);
	  } 
	  catch (IOException e) 
	  {
		  System.err.println("IOException:  " + e);
	  }
   }		   
}





*Edited to add the [ code] tags

This post has been edited by pbl: 01 December 2008 - 09:43 PM

Was This Post Helpful? 0
  • +
  • -

#12 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8332
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Passing data between clients in a multithreaded server client program

Posted 01 December 2008 - 10:03 PM

Two major glitches....

First your Server2Connection is wrong

everytime you call Server2Connection oneconnection = new Server2Connection(clientSocket, i, this);

you create a new Server2Connection object which has is own version of

Socket [] addr = new Socket [5];
PrintStream [] os = new PrintStream [5];
BufferedReader [] is = new BufferedReader [5];

you need to create a constructor for Server2Connection that will create a single instance of Server2Connection

Server2Connection connection = new Server2Connection();

then you can have a method to ADD a client

connection.add(clientSocket, i, this);

that will append in your array the new connection

Second:

while your client is waiting for user input

String keyboardInput = br.readLine();

it is not monitoring the socket to see if the server broadcast a message
Was This Post Helpful? 0
  • +
  • -

#13 always_learning  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 30-November 08

Re: Passing data between clients in a multithreaded server client program

Posted 01 December 2008 - 10:07 PM

View Postpbl, on 1 Dec, 2008 - 09:03 PM, said:

Two major glitches....

First your Server2Connection is wrong

everytime you call Server2Connection oneconnection = new Server2Connection(clientSocket, i, this);

you create a new Server2Connection object which has is own version of

Socket [] addr = new Socket [5];
PrintStream [] os = new PrintStream [5];
BufferedReader [] is = new BufferedReader [5];

you need to create a constructor for Server2Connection that will create a single instance of Server2Connection

Server2Connection connection = new Server2Connection();

then you can have a method to ADD a client

connection.add(clientSocket, i, this);

that will append in your array the new connection

Second:

while your client is waiting for user input

String keyboardInput = br.readLine();

it is not monitoring the socket to see if the server broadcast a message


Thanks for sending the solution so soon . I will try to remove the mistakes and hope it will work then .
Was This Post Helpful? 0
  • +
  • -

#14 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8332
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Passing data between clients in a multithreaded server client program

Posted 01 December 2008 - 10:24 PM

View Postalways_learning, on 1 Dec, 2008 - 09:07 PM, said:

Thanks for sending the solution so soon . I will try to remove the mistakes and hope it will work then .

No problem
Was This Post Helpful? 0
  • +
  • -

#15 always_learning  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 30-November 08

Re: Passing data between clients in a multithreaded server client program

Posted 01 December 2008 - 10:43 PM

View Postpbl, on 1 Dec, 2008 - 09:03 PM, said:

Two major glitches....

First your Server2Connection is wrong

everytime you call Server2Connection oneconnection = new Server2Connection(clientSocket, i, this);

you create a new Server2Connection object which has is own version of

Socket [] addr = new Socket [5];
PrintStream [] os = new PrintStream [5];
BufferedReader [] is = new BufferedReader [5];

you need to create a constructor for Server2Connection that will create a single instance of Server2Connection

Server2Connection connection = new Server2Connection();

then you can have a method to ADD a client

connection.add(clientSocket, i, this);

that will append in your array the new connection

Second:

while your client is waiting for user input

String keyboardInput = br.readLine();

it is not monitoring the socket to see if the server broadcast a message


Thank you so much for finding the glitches . I will try to remove them and hope it will work.
Thanks again.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1