Previous Contents Next

Chapter 7  Running The FFN Application on Multiple Nodes:

We are now going to use a new way of finding the nameserver. In the past, we have added the IOR string for an object generated to standard out to another application via clumsy manual cut and paste operations from one window to another or we have read the generated IOR strings from a file. Now suppose we wish to run a served application on node architeuthus and we wish to use this object from a client running on node shortstuff. It is very clumsy to write the IOR string to a file on node ozymanmius and then use ftp or rsh mechanisms to get this string for use on shortstuff. Instead, we will use a new protocol that works like this: we start the Name Server on a specific port with the line orbacusnameserver -OAport <some number> and follow our usual ORB initializations but with the new option ./server2 .... -ORBInit NameService=corbaloc::<host>:<port>/NameService where host is the name of the hsot we start the Name Server on and port is the integer that is the port we started the Name Server on.

7.1  New Code:

7.1.1  The New Server:

The Makefile: MakeServer2

The make file is similar to what we have seen before:

MakeServer2
 1 # ------------------------- #
 2 # Paths for this simulation #
 3 # ------------------------- #
 4 MYMAKE = MakeServer2
 5 #
 6 ORBHome = /home/peterson/orbacus
 7 BASE_PATH = ../..
 8 MY_INCLUDE_PATH = /home/peterson/programs/JimIncludes
 9 MY_LIBRARY_PATH = /home/peterson/programs/JimLibs
10 MAIN_LIBRARY_PATH = $(BASE_PATH)/JimLibs
11 MAIN_INCLUDE_PATH = $(BASE_PATH)/JimIncludes
12 ORB_INCLUDES = ${ORBHome}/include
13 ORB_LIBS = ${ORBHome}/lib
14 PROGRAM_PATH = App
15 INCLUDES = -I. -I$(ORB_INCLUDES) -I$(MY_INCLUDE_PATH) -I$(MAIN_INCLUDE_PATH)
16 
17 LIBRARY_FLAGS_SOURCES = -L$(ORB_LIBS) -L$(MY_LIBRARY_PATH) -L$(MAIN_LIBRARY_PATH)
18 SUNLIBS = -ll -lgen
19 LIBS    = -lm
20 
21 SIMLIBS = -lmystring -ltransfer -linput -llayer -lneuron -llayervec1 \
22         -lneuronvec1 -lcharvec1 -lintvec1 -ldoublevec1 -ldoublevec2 -lmatrixffn\
23         -lmystring -lNeuralNets -lCosNaming -lOB -lJTC -lpthread
24 # ----------- #
25 # Definitions #
26 # ----------- #
27 DEFINES = -fPIC -Wall -fpermissive -DX11R6
28 CC = c++
29 CXX = c++
30 LIBRARY_FLAGS_SHARED =   -shared
31 COMPILE_FLAGS_LINK = -g $(DEFINES) $(INCLUDES)
32 COMPILE_FLAGS_SOURCES = -c -g $(DEFINES) $(INCLUDES)
33 
34 RANLIB = :
35 # ------------- #
36 # Define target #
37 # ------------- #
38 TARGET = server2
39 OBJECTS = NeuralNets_impl.o\
40         server2.o
41 SOURCES = $(OBJECTS:.o=.cpp)
42 progs:
43         @make $(TARGET) -f $(MYMAKE)
44 $(TARGET): $(SOURCES) $(OBJECTS)
45         @echo
46         @echo Creating the Executible $(TARGET)
47         @echo
48         @echo $(ORBHome)
49         @echo
50         rm -f $(TARGET)
51         $(CC) $(COMPILE_FLAGS_LINK) -o $(TARGET) $(OBJECTS)\
52         $(LIBRARY_FLAGS_SOURCES) $(SIMLIBS) $(LIBS)
53 #       rm -f $(OBJECTS)        
54 # --------------------------- #
55 # 'make' template for OBJECTS #
56 # --------------------------- #
57 $(OBJECTS): $(@:.o=.cpp)
58         @echo
59         @echo Compiling $@
60         @echo
61         $(CC) $(COMPILE_FLAGS_SOURCES) $(LIBS) $(@:.o=.cpp)
62 all:
63         @make progs -f $(MYMAKE)
64 NeuralNets_impl.o:      NeuralNets_impl.h
65 server2.o:      server2.cpp


syntax highlighted by Code2HTML, v. 0.8.8b

The Code:

server2.cpp
  1 #include <stdio.h>
  2 #include <time.h>
  3 #include <iostream.h>
  4 #include <fstream.h>
  5 #include <OB/CORBA.h>
  6 #include <OB/CosNaming.h>
  7 #include "NeuralNets_skel.h"
  8 #include "NeuralNets_impl.h"
  9 #include "utility.h"
 10 
 11 #ifdef HAVE_FSTREAM
 12 #   include <fstream>
 13 #else
 14 #   include <fstream.h>
 15 #endif
 16 
 17 #ifdef HAVE_STD_IOSTREAM
 18 using namespace std;
 19 #endif
 20   
 21 int
 22 run(CORBA::ORB_ptr orb,int argc, char *argv[])
 23 {
 24     CORBA::Object_var Temp;
 25        
 26     // Get reference to Root POA.
 27     cout << "In run" << endl;
 28     cout << "resolve initial refs " << endl;
 29     CORBA::Object_var poaObj = orb->resolve_initial_references("RootPOA");
 30     
 31     cout << " set rootPoa" << endl;
 32     PortableServer::POA_var rootPoa 
 33       = PortableServer::POA::_narrow(poaObj);
 34 
 35     // Get Reference to POA manager
 36     cout << "get reference to poa manager" << endl;
 37     PortableServer::POAManager_var manager = rootPoa->the_POAManager(); 
 38     
 39     cout << "activate poa manager " << endl;
 40     manager->activate(); 
 41     
 42     cout << "get reference to initial naming context" << endl;
 43     CORBA::Object_var nsobj;
 44     nsobj = orb->resolve_initial_references("NameService");    
 45     
 46     cout << "narrow name context" << endl;
 47     CosNaming::NamingContext_var inc;
 48     inc = CosNaming::NamingContext::_narrow(nsobj);
 49           
 50     // Create an object
 51     cout << "create a NeuralNetFactory FFN Object" << endl;
 52     NeuralNets::NeuralNetFactory_impl *NeuralNetFactoryimpl 
 53       = new NeuralNets::NeuralNetFactory_impl(rootPoa);
 54     PortableServer::ServantBase_var servant = NeuralNetFactoryimpl;
 55     NeuralNets::NeuralNetFactory_var NeuralNetfactory 
 56       = NeuralNetFactoryimpl->_this();
 57     
 58     cout << "initialize the name of our object to " 
 59          << "app2.devices" << argv[1] << endl;
 60          
 61     cout << "create app2 context " << endl;
 62     CosNaming::NamingContext_var app2;         
 63     CosNaming::Name name;
 64     name.length(1);
 65     name[0].id = CORBA::string_dup("app2");
 66     name[0].kind = CORBA::string_dup("");   
 67     cout << "bind context for app2" << endl;
 68     app2 = inc->bind_new_context(name);
 69 
 70     CosNaming::NamingContext_var devices;    
 71     name[0].id = CORBA::string_dup("devices");
 72     name[0].kind = CORBA::string_dup("");     
 73     cout << "bind context for devices" << endl;
 74     devices = app2->bind_new_context(name); 
 75 
 76     cout << "Set up last name field to be " << argv[1] << endl;
 77     name[0].id = CORBA::string_dup(argv[1]);
 78     name[0].kind = CORBA::string_dup("");
 79             
 80     try{ 
 81       cout << "bind NeuralNetfactory object" << endl;  
 82       devices->bind(name,NeuralNetfactory);
 83       }
 84     catch(const CORBA::Exception& ex){
 85       cout << "object " << argv[1] << " is already running!" << endl;     
 86       }  
 87 
 88     // Accept requests
 89     cout << "run orb" << endl;
 90     orb->run();
 91 
 92     return EXIT_SUCCESS;
 93 }
 94 
 95 int main(int argc, char* argv[])
 96 {
 97   int status = 0;
 98   CORBA::ORB_var orb;
 99   
100   //======================================================//
101   // For our Orbacus server we start up with
102   // ./server2:                            this is argv[0]
103   // option 1 <name of our server object>: this is argv[1]
104   // option 2 -OAbind ip address:          this is argv[2] 
105   //                                         and argv[3]
106   // option 3 -OAport port number          this is argv[4]
107   //                                            and argv[5]  
108   // option 4 -OAhost hostname:            this is argv[6] 
109   //                                         and argv[7] 
110   // option 5 -ORBtrace_connections 1      this is argv[8] 
111   //                                         and argv[9]
112   // option 6 -ORBInitRef                  this is argv[10]
113   //   NameService=corbaloc::<hostname>:<port>/NameService
114   //                                       this is argv[11]
115   //======================================================//
116   if(argc!=12){
117     cout << "start server as ./server2 opt1 opt2 opt3 opt4 opt5 opt6" << endl;
118     cout << "  where opt1 = <name of our served object>" << endl;
119     cout << "  where opt2 = -OAbind <ip address of host> " << endl;
120     cout << "  where opt3 = -OAport <port number> " << endl;
121     cout << "  where opt4 = -OAhost <host name> " << endl;
122     cout << "  where opt5 = -ORBtrace_connections 1 " << endl;
123     cout << "  where opt6 = -ORBInitRef NameService = " << endl;
124     cout << "           corbaloc::<hostname>:<port>/NameService " << endl;     
125     exit(-1);
126     }
127   else{
128     for(int p=0;p<argc;++p)
129       cout << "argv[" << p << "] = " << argv[p] << endl;
130     }
131 
132   try{    
133     //initialize orb
134     cout << "Initialize orb" << endl;
135     orb = CORBA::ORB_init(argc,argv);   
136              
137     cout << "Call run" << endl;
138     status = run(orb,argc,argv);
139     }
140   catch(const CORBA::Exception& ex){ 
141     cerr << ex << endl;
142     status = EXIT_FAILURE;
143     }
144   if(!CORBA::is_nil(orb)){
145     try{
146       orb -> destroy();
147       }
148     catch(const CORBA::Exception& ex){
149       cerr << ex << endl;
150       status = EXIT_FAILURE;
151       }
152     }
153   return status;
154 }


syntax highlighted by Code2HTML, v. 0.8.8b

7.1.2  The New Client:

The New Makefile: MakeClient2:

The make file is similar to what we have seen before:

MakeClient2
 1 # ------------------------- #
 2 # Paths for this simulation #
 3 # ------------------------- #
 4 MYMAKE = MakeClient2
 5 #
 6 ORBHome = /home/peterson/orbacus
 7 BASE_PATH = ../..
 8 MY_INCLUDE_PATH = /home/peterson/programs/JimIncludes
 9 MY_LIBRARY_PATH = /home/peterson/programs/JimLibs
10 MAIN_LIBRARY_PATH = $(BASE_PATH)/JimLibs
11 MAIN_INCLUDE_PATH = $(BASE_PATH)/JimIncludes
12 ORB_INCLUDES = ${ORBHome}/include
13 ORB_LIBS = ${ORBHome}/lib
14 PROGRAM_PATH = App
15 INCLUDES = -I. -I$(ORB_INCLUDES) -I$(MY_INCLUDE_PATH) -I$(MAIN_INCLUDE_PATH)
16 
17 LIBRARY_FLAGS_SOURCES = -L$(ORB_LIBS) -L$(MY_LIBRARY_PATH) -L$(MAIN_LIBRARY_PATH)
18 SUNLIBS = -ll -lgen
19 LIBS    = -lm
20 SIMLIBS = -lNeuralNets -lCosNaming -lOB -lJTC -lpthread
21 
22 # ----------- #
23 # Definitions #
24 # ----------- #
25 DEFINES = -fPIC -Wall -fpermissive -DX11R6
26 CC = gcc
27 CXX = c++
28 LIBRARY_FLAGS_SHARED =   -shared
29 COMPILE_FLAGS_LINK = -g $(DEFINES) $(INCLUDES)
30 COMPILE_FLAGS_SOURCES = -c -g $(DEFINES) $(INCLUDES)
31 
32 RANLIB = :
33 # ------------- #
34 # Define target #
35 # ------------- #
36 TARGET = client2
37 OBJECTS = client2.o
38 SOURCES = $(OBJECTS:.o=.cpp)
39 progs:
40         @make $(TARGET) -f $(MYMAKE)
41 $(TARGET): $(SOURCES) $(OBJECTS)
42         @echo
43         @echo Creating the Executible $(TARGET)
44         @echo
45         @echo $(ORBHome)
46         @echo
47         rm -f $(TARGET)
48         $(CC) $(COMPILE_FLAGS_LINK) -o $(TARGET) $(OBJECTS)\
49         $(LIBRARY_FLAGS_SOURCES) $(SIMLIBS) $(LIBS)
50 #       rm -f $(OBJECTS)        
51 # --------------------------- #
52 # 'make' template for OBJECTS #
53 # --------------------------- #
54 $(OBJECTS): $(@:.o=.cpp)
55         @echo
56         @echo Compiling $@
57         @echo
58         $(CC) $(COMPILE_FLAGS_SOURCES) $(LIBS) $(@:.o=.cpp)
59 all:
60         @make progs -f $(MYMAKE)
61 client2.o:      client2.cpp


syntax highlighted by Code2HTML, v. 0.8.8b

The New Code:

client2.cpp
  1 #include <stdio.h>
  2 #include <time.h>
  3 #include <iostream.h>
  4 #include <fstream.h>
  5 #include "mystring.h"
  6 #include "charvec1.h"
  7 #include <OB/CORBA.h>
  8 #include <OB/CosNaming.h>
  9 #include "NeuralNets.h"
 10 #include "NeuralNets_impl.h"
 11 #include "utility.h"
 12 
 13 int run(CORBA::ORB_ptr orb, int argc, char* argv[])
 14 {
 15 
 16   CORBA::Object_var Temp;
 17   
 18   cout << "get reference to initial naming context" << endl;
 19   CORBA::Object_var nsobj;
 20   nsobj = orb->resolve_initial_references("NameService");    
 21     
 22   cout << "narrow name context" << endl;
 23   CosNaming::NamingContext_var inc;
 24   inc = CosNaming::NamingContext::_narrow(nsobj);
 25       
 26   cout << "initialize the name of our object to look for to " 
 27        << argv[1] << endl;
 28   CosNaming::Name name;
 29   name.length(3);
 30   name[0].id = CORBA::string_dup("app2");
 31   name[0].kind = CORBA::string_dup("");
 32   name[1].id = CORBA::string_dup("devices");
 33   name[1].kind = CORBA::string_dup("");
 34   name[2].id = CORBA::string_dup(argv[1]);
 35   name[2].kind = CORBA::string_dup("");  
 36   
 37   cout << "resolve name" << endl;
 38   try{  
 39     cout << "resolve new context" << endl;
 40     Temp = inc->resolve(name); 
 41     }
 42   catch(const CosNaming::NamingContext::NotFound&){
 43     cerr << "No name for object" << endl;
 44     throw 0; 
 45     } 
 46   catch(const CORBA::Exception& e){
 47     cerr << "resolve failed" << e << endl;
 48     throw 0;
 49     } 
 50     
 51   if(CORBA::is_nil(Temp)){
 52     cerr << "Nil reference for server object" << endl;
 53     throw 0;
 54     }
 55     
 56   cout << "narrow to NeuralNetFactory" << endl;
 57   NeuralNets::NeuralNetFactory_var NeuralNetfactory;
 58   try{
 59     NeuralNetfactory = NeuralNets::NeuralNetFactory::_narrow(Temp);
 60     }
 61   catch(const CORBA::Exception& e){
 62     cerr << "cannot narrow NeuralNetfactory reference" << e << endl;
 63     throw 0;
 64     }  
 65   if(CORBA::is_nil(NeuralNetfactory)){
 66     cerr << "mytime reference is of wrong type" << endl;
 67     throw 0;
 68     }
 69     
 70   cout << "******************************************" << endl;    
 71   cout << "use NeuralNetfactory reference to " << endl;
 72   cout << "create a FFN Object:" << endl;
 73   NeuralNets::FFN_ptr ffn = NeuralNetfactory->CreateFFN();
 74   ffn->run("config.txt");
 75                         
 76   return 0;
 77 }
 78 
 79 int main(int argc, char* argv[])
 80 {
 81   int status = 0;
 82   CORBA::ORB_var orb;
 83   
 84   int check_ior = 1;    
 85   int dummy_argc;
 86   char *dummy_argv[10];
 87 
 88   //======================================================//
 89   // For our Orbacus client we start up with
 90   // ./client2:                            this is argv[0]
 91   // option 1 <name of our server object>: this is argv[1]
 92   // option 2 -OAbind ip address:          this is argv[2] 
 93   //                                         and argv[3]
 94   // option 3 -OAport port number          this is argv[4]
 95   //                                            and argv[5]  
 96   // option 4 -OAhost hostname:            this is argv[6] 
 97   //                                         and argv[7] 
 98   // option 5 -ORBtrace_connections 1      this is argv[8] 
 99   //                                         and argv[9]
100   // option 6 -ORBInitRef                  this is argv[10]
101   //   NameService=corbaloc::<hostname>:<port>/NameService
102   //                                       this is argv[11]
103   //======================================================//
104   if(argc!=12){
105     cout << "start server as ./server2 opt1 opt2 opt3 opt4 opt5 opt6" << endl;
106     cout << "  where opt1 = <name of our served object>" << endl;
107     cout << "  where opt2 = -OAbind <ip address of host> " << endl;
108     cout << "  where opt3 = -OAport <port number> " << endl;
109     cout << "  where opt4 = -OAhost <host name> " << endl;
110     cout << "  where opt5 = -ORBtrace_connections 1 " << endl;
111     cout << "  where opt6 = -ORBInitRef NameService = " << endl;
112     cout << "           corbaloc::<hostname>:<port>/NameService " << endl;     
113     exit(-1);
114     }
115   else{
116     for(int p=0;p<argc;++p)
117       cout << "argv[" << p << "] = " << argv[p] << endl;
118     }
119 
120   try{ 
121     //initialize orb
122     cout << "Initialize orb" << endl;
123     orb = CORBA::ORB_init(argc,argv);   
124              
125     cout << "Call run" << endl;
126     status = run(orb,argc,argv);  
127     }
128   catch(const CORBA::Exception& ex){ 
129     cerr << ex << endl;
130     status = EXIT_FAILURE;
131     }
132   if(!CORBA::is_nil(orb)){
133     try{
134       orb -> destroy();
135       }
136     catch(const CORBA::Exception& ex){
137       cerr << ex << endl;
138       status = EXIT_FAILURE;
139       }
140     }
141   return status;  
142 }


syntax highlighted by Code2HTML, v. 0.8.8b

7.1.3  The Unbind Code:

The New Makefile: MakeServer2Unbind:

The make file is as follows:

MakeServer2Unbind
 1 # ------------------------- #
 2 # Paths for this simulation #
 3 # ------------------------- #
 4 MYMAKE = MakeServer2Unbind
 5 #
 6 ORBHome = /home/peterson/orbacus
 7 BASE_PATH = ../..
 8 MY_INCLUDE_PATH = /home/peterson/programs/JimIncludes
 9 MY_LIBRARY_PATH = /home/peterson/programs/JimLibs
10 MAIN_LIBRARY_PATH = $(BASE_PATH)/JimLibs
11 MAIN_INCLUDE_PATH = $(BASE_PATH)/JimIncludes
12 ORB_INCLUDES = ${ORBHome}/include
13 ORB_LIBS = ${ORBHome}/lib
14 PROGRAM_PATH = App
15 INCLUDES = -I. -I$(ORB_INCLUDES) -I$(MY_INCLUDE_PATH) -I$(MAIN_INCLUDE_PATH)
16 
17 LIBRARY_FLAGS_SOURCES = -L$(ORB_LIBS) -L$(MY_LIBRARY_PATH) -L$(MAIN_LIBRARY_PATH)
18 SUNLIBS = -ll -lgen
19 LIBS    = -lm
20 
21 SIMLIBS = -lCosNaming -lOB -lJTC -lpthread
22 # ----------- #
23 # Definitions #
24 # ----------- #
25 DEFINES = -fPIC -Wall -fpermissive -DX11R6
26 CC = c++
27 CXX = c++
28 LIBRARY_FLAGS_SHARED =   -shared
29 COMPILE_FLAGS_LINK = -g $(DEFINES) $(INCLUDES)
30 COMPILE_FLAGS_SOURCES = -c -g $(DEFINES) $(INCLUDES)
31 
32 RANLIB = :
33 # ------------- #
34 # Define target #
35 # ------------- #
36 TARGET = server2unbind
37 OBJECTS = server2unbind.o
38 SOURCES = $(OBJECTS:.o=.cpp)
39 progs:
40         @make $(TARGET) -f $(MYMAKE)
41 $(TARGET): $(SOURCES) $(OBJECTS)
42         @echo
43         @echo Creating the Executible $(TARGET)
44         @echo
45         @echo $(ORBHome)
46         @echo
47         rm -f $(TARGET)
48         $(CC) $(COMPILE_FLAGS_LINK) -o $(TARGET) $(OBJECTS)\
49         $(LIBRARY_FLAGS_SOURCES) $(SIMLIBS) $(LIBS)
50 #       rm -f $(OBJECTS)        
51 # --------------------------- #
52 # 'make' template for OBJECTS #
53 # --------------------------- #
54 $(OBJECTS): $(@:.o=.cpp)
55         @echo
56         @echo Compiling $@
57         @echo
58         $(CC) $(COMPILE_FLAGS_SOURCES) $(LIBS) $(@:.o=.cpp)
59 all:
60         @make progs -f $(MYMAKE)
61 serverunbind.o: server2unbind.cpp


syntax highlighted by Code2HTML, v. 0.8.8b

The Unbind Code:

After the server object is destroyed, we must still remove the full name path for the object that has been stored in the Name Service. The code to do that is below:

server2unbind.cpp
  1 #include <stdio.h>
  2 #include <iostream.h>
  3 #include <fstream.h>
  4 #include <OB/CORBA.h>
  5 #include <OB/CosNaming.h>
  6 
  7 #ifdef HAVE_FSTREAM
  8 #   include <fstream>
  9 #else
 10 #   include <fstream.h>
 11 #endif
 12 
 13 #ifdef HAVE_STD_IOSTREAM
 14 using namespace std;
 15 #endif
 16   
 17 int
 18 run(CORBA::ORB_ptr orb,int argc, char *argv[])
 19 {
 20     CORBA::Object_var Temp;
 21        
 22     // Get reference to Root POA.
 23     cout << "In run" << endl;
 24     cout << "resolve initial refs " << endl;
 25     CORBA::Object_var poaObj = orb->resolve_initial_references("RootPOA");
 26     
 27     cout << " set rootPoa" << endl;
 28     PortableServer::POA_var rootPoa 
 29       = PortableServer::POA::_narrow(poaObj);
 30 
 31     // Get Reference to POA manager
 32     cout << "get reference to poa manager" << endl;
 33     PortableServer::POAManager_var manager = rootPoa->the_POAManager(); 
 34     
 35     cout << "activate poa manager " << endl;
 36     manager->activate(); 
 37     
 38     cout << "get reference to initial naming context" << endl;
 39     CORBA::Object_var nsobj;
 40     nsobj = orb->resolve_initial_references("NameService");    
 41     
 42     cout << "narrow name context" << endl;
 43     CosNaming::NamingContext_var inc;
 44     inc = CosNaming::NamingContext::_narrow(nsobj);
 45 
 46     cout << "initialize the name of our object to look for to " 
 47          << argv[1] << endl;
 48     CosNaming::Name name;
 49     name.length(3);
 50     name[0].id = CORBA::string_dup("app2");
 51     name[0].kind = CORBA::string_dup("");
 52     name[1].id = CORBA::string_dup("devices");
 53     name[1].kind = CORBA::string_dup("");
 54     name[2].id = CORBA::string_dup(argv[1]);
 55     name[2].kind = CORBA::string_dup("");
 56                      
 57     cout << "object " << argv[1] << " is already running!" << endl;     
 58     cout << "  so unbind object app2->devices->" << argv[1] << endl;    
 59     inc->unbind(name);
 60 
 61     cout << "remove rest of context tree" << endl;
 62     CosNaming::Name name2;
 63     name2.length(2);
 64 
 65     cout << "remove app2->devices" << endl;
 66     name2[0].id = CORBA::string_dup("app2");
 67     name2[0].kind = CORBA::string_dup(""); 
 68     name2[1].id = CORBA::string_dup("devices");
 69     name2[1].kind = CORBA::string_dup("");
 70     inc->unbind(name2);
 71 
 72     cout << "remove app2 " << endl;
 73     CosNaming::Name name3;
 74     name3.length(1);
 75     name3[0].id = CORBA::string_dup("app2");
 76     name3[0].kind = CORBA::string_dup(""); 
 77     inc->unbind(name3); 
 78 
 79     return EXIT_SUCCESS;
 80 }
 81 
 82 int main(int argc, char* argv[])
 83 {
 84   int status = 0;
 85   CORBA::ORB_var orb;
 86   
 87   //======================================================//
 88   // For our Orbacus server we start up with
 89   // ./server2:                            this is argv[0]
 90   // option 1 <name of our server object>: this is argv[1]
 91   // option 2 -OAbind ip address:          this is argv[2] 
 92   //                                         and argv[3]
 93   // option 3 -OAport port number          this is argv[4]
 94   //                                            and argv[5]  
 95   // option 4 -OAhost hostname:            this is argv[6] 
 96   //                                         and argv[7] 
 97   // option 5 -ORBtrace_connections 1      this is argv[8] 
 98   //                                         and argv[9]
 99   // option 6 -ORBInitRef                  this is argv[10]
100   //   NameService=corbaloc::<hostname>:<port>/NameService
101   //                                       this is argv[11]
102   //======================================================//
103   if(argc!=12){
104     cout << "start server as ./server2 opt1 opt2 opt3 opt4 opt5 opt6" << endl;
105     cout << "  where opt1 = <name of our served object>" << endl;
106     cout << "  where opt2 = -OAbind <ip address of host> " << endl;
107     cout << "  where opt3 = -OAport <port number> " << endl;
108     cout << "  where opt4 = -OAhost <host name> " << endl;
109     cout << "  where opt5 = -ORBtrace_connections 1 " << endl;
110     cout << "  where opt6 = -ORBInitRef NameService = " << endl;
111     cout << "           corbaloc::<hostname>:<port>/NameService " << endl;     
112     exit(-1);
113     }
114   else{
115     for(int p=0;p<argc;++p)
116       cout << "argv[" << p << "] = " << argv[p] << endl;
117     }
118 
119   try{    
120     //initialize orb
121     cout << "Initialize orb" << endl;
122     orb = CORBA::ORB_init(argc,argv);   
123              
124     cout << "Call run" << endl;
125     status = run(orb,argc,argv);
126     }
127   catch(const CORBA::Exception& ex){ 
128     cerr << ex << endl;
129     status = EXIT_FAILURE;
130     }
131   if(!CORBA::is_nil(orb)){
132     try{
133       orb -> destroy();
134       }
135     catch(const CORBA::Exception& ex){
136       cerr << ex << endl;
137       status = EXIT_FAILURE;
138       }
139     }
140   return status;
141 }


syntax highlighted by Code2HTML, v. 0.8.8b

7.2  The Run Time:

7.2.1  Start the Name Server:

Start nameserver on port 3500 using default host architeuthus

[petersj@architeuthus App]$ orbacusnameserver -OAport 3500 &
[8] 25375
[petersj@architeuthus App]$

Look and see if nameserver is running 

[petersj@architeuthus App]$ ps -ef

petersj 25375 16686  1 08:24 pts/3    00:00:00 
   /home/petersj/orbacus/bin/nameserv -OAport 3500
petersj 25376 25375  0 08:24 pts/3    00:00:00 
  /home/petersj/orbacus/bin/nameserv -OAport 3500
petersj 25377 25376  0 08:24 pts/3    00:00:00 
  /home/petersj/orbacus/bin/nameserv -OAport 3500

7.2.2  Start the Server on architeuthus:

Start server on port 5000 using this name server

[petersj@architeuthus App]$ 
./server2 MyFFN -OAbind 192.168.0.5 
                -OAport 5000 
                -OAhost architeuthus 
                -ORBtrace_connections 1 
                 -ORBInitRef NameService=corbaloc::architeuthus:3500/NameService&

7.2.3  Unbind the Served Object:

Now check to see if we can unbind this name:


First find the server

[petersj@architeuthus App]$ ps -ef

petersj 25380 16686 16 08:29 pts/3    00:00:00 ./server2 MyFFN -OAbind 192.168.0.5 -OAport 5000 -Opetersj 25383 25376  0 08:29 pts/3    00:00:00 
         /home/petersj/orbacus/bin/nameserv -OAport 3500

Kill the server

[petersj@architeuthus App]$ kill -9 25380

[11]   Killed                        
./server2 MyFFN -OAbind 192.168.0.5 -OAport 5000 -OAhost architeuthus  ...


Now unbind the name:

[petersj@architeuthus App]$ ./server2unbind MyFFN -OAbind 192.168.0.5 -OAport 5000 -OAhost architeuthus -ORBtrace_connections 1 -ORBInitRef NameService=corbaloc::architeuthus:3500/NameService &
[11] 25394
[petersj@architeuthus App]$ argv[0] = ./server2unbind
argv[1] = MyFFN
argv[2] = -OAbind
argv[3] = 192.168.0.5
argv[4] = -OAport
argv[5] = 5000
argv[6] = -OAhost
argv[7] = architeuthus
argv[8] = -ORBtrace_connections
argv[9] = 1
argv[10] = -ORBInitRef
argv[11] = NameService=corbaloc::architeuthus:3500/NameService
Initialize orb
Call run
In run
resolve initial refs 
[ incoming: accepting connections
  id: TAG_IIOP
  local address: 192.168.0.5:5000
  hosts: architeuthus ]
 set rootPoa
get reference to poa manager
activate poa manager 
get reference to initial naming context
narrow name context
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 192.168.0.5:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 192.168.0.5:3554
  remote address: 192.168.0.5:3500 ]
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 192.168.0.5:3554
  remote address: 192.168.0.5:3500 ]
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 192.168.0.5:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 192.168.0.5:3555
  remote address: 192.168.0.5:3500 ]
initialize the name of our object to look for to MyFFN
object MyFFN is already running!
  so unbind object app2->devices->MyFFN
remove rest of context tree
remove app2->devices
remove app2 
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 192.168.0.5:3555
  remote address: 192.168.0.5:3500 ]
[ incoming: stopped accepting connections
  id: TAG_IIOP
  local address: 192.168.0.5:5000
  hosts: architeuthus ]

[11]   Done                          
./server2unbind MyFFN -OAbind 192.168.0.5 -OAport 5000 -OAhost architeuthus  ...
[petersj@architeuthus App]$ 

7.2.4  Restart the Server on architeuthus:

Now restart server

[petersj@architeuthus App]$ ./server2 MyFFN -OAbind 192.168.0.5 -OAport 5000 -OAhost architeuthus -ORBtrace_connections 1 -ORBInitRef NameService=corbaloc::architeuthus:3500/NameService &
[11] 25404
[petersj@architeuthus App]$ argv[0] = ./server2
argv[1] = MyFFN
argv[2] = -OAbind
argv[3] = 192.168.0.5
argv[4] = -OAport
argv[5] = 5000
argv[6] = -OAhost
argv[7] = architeuthus
argv[8] = -ORBtrace_connections
argv[9] = 1
argv[10] = -ORBInitRef
argv[11] = NameService=corbaloc::architeuthus:3500/NameService
Initialize orb
Call run
In run
resolve initial refs 
[ incoming: accepting connections
  id: TAG_IIOP
  local address: 192.168.0.5:5000
  hosts: architeuthus ]
 set rootPoa
get reference to poa manager
activate poa manager 
get reference to initial naming context
narrow name context
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 192.168.0.5:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 192.168.0.5:3556
  remote address: 192.168.0.5:3500 ]
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 192.168.0.5:3556
  remote address: 192.168.0.5:3500 ]
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 192.168.0.5:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 192.168.0.5:3557
  remote address: 192.168.0.5:3500 ]
create a NeuralNetFactory FFN Object
initialize the name of our object to app2.devicesMyFFN
create app2 context 
bind context for app2
bind context for devices
Set up last name field to be MyFFN
bind NeuralNetfactory object
run orb

[petersj@architeuthus App]$ 

7.2.5  Run the Client on shortstuff:

Run client on laptop

[petersj@shortstuff App]$ ./client2 MyFFN -OAbind 192.168.0.1 -OAport 3500 -OAhost shortstuff -ORBtrace_connections 1 -ORBInitRef NameService=corbaloc::architeuthus:3500/NameService
argv[0] = ./client2
argv[1] = MyFFN
argv[2] = -OAbind
argv[3] = 192.168.0.1
argv[4] = -OAport
argv[5] = 3500
argv[6] = -OAhost
argv[7] = shortstuff
argv[8] = -ORBtrace_connections
argv[9] = 1
argv[10] = -ORBInitRef
argv[11] = NameService=corbaloc::architeuthus:3500/NameService
Initialize orb
Call run
get reference to initial naming context
narrow name context
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 192.168.0.5:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 192.168.0.1:1050
  remote address: 192.168.0.5:3500 ]
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 192.168.0.1:1050
  remote address: 192.168.0.5:3500 ]
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 192.168.0.5:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 192.168.0.1:1051
  remote address: 192.168.0.5:3500 ]
initialize the name of our object to look for to MyFFN
resolve name
resolve new context
narrow to NeuralNetFactory
******************************************
use NeuralNetfactory reference to 
create a FFN Object:
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 192.168.0.5:5000 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 192.168.0.1:1052
  remote address: 192.168.0.5:5000 ]
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 192.168.0.1:1051
  remote address: 192.168.0.5:3500 ]
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 192.168.0.1:1052
  remote address: 192.168.0.5:5000 ]

7.2.6  What The Server on architeuthus Shows:

[petersj@architeuthus App]$ [ incoming: new connection
  id: TAG_IIOP
  local address: 192.168.0.5:5000
  remote address: 192.168.0.1:1055 ]
NeuralNetsFactory:: create a FFN Object
create NeuralNets::FFN_impl *FFNimpl
   = new NeuralNets::FFN_impl(poa_)
return FFN object
  call return FFNimpl->_this();
config_file = config.txt
init string is config.txt
INPUT Base Object Configuration File is input_base.cfg
INPUT FFN Object Configuration File is input.cfg
startup file = config.txt  name_file_used_to_launch_application:
init file = input_base.cfg  name_of_file_used_to_store_tuneable_parameters:
neuron specific file = specific.cfg  name_of_file_used_to_store_neuron_specific_data:
start weight file = weights.dat  weight_initialization_file:
weight file = weights.dat  write_weights_to_this_file:
training file = 90trna.cop  training_file:
testing file = 10tena.cop  testing_file:
time_seed = 0  random_time_seed_1_is_yes:
print_freq = 20  learning_results_print_frequency:
weight_freq = 20  weights_print_to_file_frequency:
read_in_weights = 1  read_in_weights_1_is_yes:
do_train = 1  do_training_1_is_yes:
snapshot_print = 0  synopsis_print_print_summary_of_results:
in_dimensions = 32  in_dimensions:
out_dimensions = 11  out_dimensions:
input_set_size = 99  training_set_size:
test_set_size  = 11  test_set_size:
test_nn = 1  test_FFN_with_data_1_is_yes:
run_limit = 1  run_limit:
learning_rate = 0.4  learning_rate:
energy_wt =1  energy_weight:
stop_tol = 0.1  stopping_tolerance:
startup ffn_file = input.cfg  file__used_to_set_ffn:
random_synapse_base =0.05  random_synapse_base:
random_gain_base = -2  random_gain_base:
random_off_base = 0.8  random_offset_base:
synapse_base_wt = 0  synapse_base_weight:
gain_base_wt = 1  gain_base_weight:
off_base_wt = 1.5  offset_base_weight:
prinit_off_gain = 0  print_the_initial_offset_and_gains_1_is_yes:
prconnect = 0  print_initial_random_synaptic_weights_1_is_yes:
prio = 0  print_I/O_pairs_in_input_list_1_is_yes:
priolayer = 0  print_I/O_pair_results_per_neuron_1_is_yes:
do_hidden_gain = 1  hidden_layer_gain_updates_1_is_yes:
do_output_gain = 1  output_layer_gain_updates_1_is_yes:
do_grad = 1  use_gradient_descent_1_is_yes:
do_norm = 1  normalize_gradients_1_is_yes:
do_deriv = 0  print_descent_vector_1_is_yes:
pr_alloc = 0  print_memory_allocation_trail_1_is_yes:
prlayer2layer = 0  print_weight_updates_for_layers_1_is_yes:
num_hidden = 1  number_of_hidden_layers:
binary = 11  number_of_binary_output_neurons:
input_gain = 1  initial_input_layer_gain:
input_offset = 2  initial_input_layer_offset:
init_neuron_gain = -2.5  initial_gain_for_other_layers:
final_neuron_gain = -2.5  final_neuron_gain:
neuron_offset = 2  initial_neuron_offsets:
number of hidden layer = 1
size of num_hl = 3
Neurons in Layer 0 = 32
Neurons in Layer 1 = 7
Neurons in Layer 2 = 11
32 7 11 

Construct NEURON_VECTOR of size 32
Construct NEURON_VECTOR of size 7
Construct NEURON_VECTOR of size 11
Construct weight matrix layer 0to 1
 of size 32 by 7
Construct weight matrix layer 1to 2
 of size 7 by 11
size = 337
name of data file: 90trna.cop
Layer[0].neurons_in_layer = 32
Sample size = 99
in size3168
out size1089
name of data file: 10tena.cop
Layer[0].neurons_in_layer = 32
Sample size = 11
in size352
out size121
TRAINING(99)
32bad binary
67.6768 percent correct
analog_en = 0
 energy = 20.8066
 rms = 0.138225
TESTING(11)
3bad binary
72.7273 percent correct
analog_en = 0
 energy = 2.2623
 rms = 0.136736
run_count = 0
learning = 0.4
grad_norm = 16.9302
Error for iteration 0is 20.8066
Previous Error for iteration 0is 20.8066
TRAINING(99)
40bad binary
59.596 percent correct
analog_en = 0
 energy = 24.5509
 rms = 0.150148
TESTING(11)
4bad binary
63.6364 percent correct
analog_en = 0
 energy = 2.42695
 rms = 0.141624

back propagation finished

run_count = 1
learning = 0.4
grad_norm = 16.9302
Error for iteration 1is 20.8066
Previous Error for iteration 1is 20.8066
TRAINING(99)
40bad binary
59.596 percent correct
analog_en = 0
 energy = 24.5509
 rms = 0.150148
TESTING(11)
4bad binary
63.6364 percent correct
analog_en = 0
 energy = 2.42695
 rms = 0.141624

 writing synaptic weights to file
finished training or never trained
run_count = 1
learning = 0.4
grad_norm = 16.9302
Error for iteration 1is 20.8066
Previous Error for iteration 1is 20.8066
TRAINING(99)
40bad binary
59.596 percent correct
analog_en = 0
 energy = 24.5509
 rms = 0.150148
TESTING(11)
4bad binary
63.6364 percent correct
analog_en = 0
 energy = 2.42695
rms = 0.141624


 writing synaptic weights to file
[ incoming: closing connection
  id: TAG_IIOP
  local address: 192.168.0.5:5000
  remote address: 192.168.0.1:1055 ]

7.3  RunTime Deja Vu:

Now we will run the server on a SUN workstation named albert and run the client on the master cluster node architeuthus.

Generating the Server on albert:

The installation of the Orbacus ORB on the ultra 1 albert was very straightforward. All of the makefiles and so forth were just as before with the exception that at run time, we had to link in an additional library for the server and client. The server needed us to link in the real time library, librt and the client needed the socket library, libsock.

Starting the Name Server on albert:

We start the Name Service on port 3500 using default host albert as follows:
albert% which orbacusnameserver
orbacusnameserver:       aliased to /local2/petersj/orbacus/bin/nameserv
albert% orbacusnameserver -OAport 3500&
[2] 5957
Now look and see if nameserver is running:
albert%ps -ef | grep "nameserv"
 petersj  5957  5929  0 11:41:52 pts/5    
          0:01 /local2/petersj/orbacus/bin/nameserv -OAport 3500

Start the server on albert:

Next, start the server on port 5000 using this name server. First, for convenience, we put all the command line stuff in an executible script: RunServer (we will not show the startup messages this time):
#!/usr/local/bin/tcsh
./server2 MyFFN -OAbind 130.127.112.116 -OAport 5000 -OAhost albert\
 -ORBtrace_connections 1\
 -ORBInitRef NameService=corbaloc::albert:3500/NameService&
Then, we start the server by just typing ./RunServer.

Unbinding the Server Name on albert:

Now check to see if we can unbind this name:

First find the server
 petersj  5990     1  0 11:48:59 pts/5    0:01 
    ./server2 MyFFN -OAbind 130.127.112.116 
    -OAport 5000 -OAhost albert -ORBtrace_c...
Now kill the server:
   
albert% kill -9 5990
Now unbind the name: we put our command line arguments in a simple executible file RunUnbind:
#!/usr/local/bin/tcsh
./server2unbind MyFFN -OAbind 130.127.112.116 -OAport 5000 -OAhost albert\
 -ORBtrace_connections 1\
 -ORBInitRef NameService=corbaloc::albert:3500/NameService&
Now run unbind: this will destroy the full name path for our bound object.
 
albert% RunUnbind
[1] 6007
albert% argv[0] = ./server2unbind
argv[1] = MyFFN
argv[2] = -OAbind
argv[3] = 130.127.112.116
argv[4] = -OAport
argv[5] = 5000
argv[6] = -OAhost
argv[7] = albert
argv[8] = -ORBtrace_connections
argv[9] = 1
argv[10] = -ORBInitRef
argv[11] = NameService=corbaloc::albert:3500/NameService
Initialize orb
Call run
In run
resolve initial refs 
[ incoming: accepting connections
  id: TAG_IIOP
  local address: 130.127.112.116:5000
  hosts: albert ]
 set rootPoa
get reference to poa manager
activate poa manager 
get reference to initial naming context
narrow name context
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 130.127.112.116:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 130.127.112.116:33087
  remote address: 130.127.112.116:3500 ]

[ outgoing: closing connection
  id: TAG_IIOP
  local address: 130.127.112.116:33087
  remote address: 130.127.112.116:3500 ]
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 130.127.112.116:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 130.127.112.116:33088
  remote address: 130.127.112.116:3500 ]
initialize the name of our object to look for to MyFFN
Unbind object app2->devices->MyFFN
remove rest of context tree
remove app2->devices
remove app2 
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 130.127.112.116:33088
  remote address: 130.127.112.116:3500 ]
[ incoming: stopped accepting connections
  id: TAG_IIOP
  local address: 130.127.112.116:5000
  hosts: albert ]

Restart the server on albert:

Now restart server: we will show the startup messages this time:
 
albert% RunServer
[1] 6016
albert% argv[0] = ./server2
argv[1] = MyFFN
argv[2] = -OAbind
argv[3] = 130.127.112.116
argv[4] = -OAport
argv[5] = 5000
argv[6] = -OAhost
argv[7] = albert
argv[8] = -ORBtrace_connections
argv[9] = 1
argv[10] = -ORBInitRef
argv[11] = NameService=corbaloc::albert:3500/NameService
Initialize orb
Call run
In run
resolve initial refs 
[ incoming: accepting connections
  id: TAG_IIOP
  local address: 130.127.112.116:5000
  hosts: albert ]
 set rootPoa
get reference to poa manager
activate poa manager 
get reference to initial naming context
narrow name context
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address:130.127.112.116:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 130.127.112.116:33089
  remote address: 130.127.112.116:3500 ]
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 130.127.112.116:33089
  remote address: 130.127.112.116:3500 ]
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 130.127.112.116:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 130.127.112.116:33090
  remote address: 130.127.112.116:3500 ]
create a NeuralNetFactory FFN Object
initialize the name of our object to app2.devicesMyFFN
create app2 context 
bind context for app2
bind context for devices
Set up last name field to be MyFFN
bind NeuralNetfactory object
run orb

Run a client on architeuthus:

Now we run a client on architeuthus: We place command line arguments in the executible file RunClient:
#!/bin/tcsh
./client2 MyFFN -OAbind 192.168.0.5 -OAport 5000 -OAhost architeuthus\
 -ORBtrace_connections 1\
 -ORBInitRef NameService=corbaloc::albert:3500/NameService&
and then start the client as follows:
[petersj@architeuthus App]$ RunClient
[1] 5151
[petersj@architeuthus App]$ argv[0] = ./client2
argv[1] = MyFFN
argv[2] = -OAbind
argv[3] = 192.168.0.5
argv[4] = -OAport
argv[5] = 5000
argv[6] = -OAhost
argv[7] = architeuthus
argv[8] = -ORBtrace_connections
argv[9] = 1
argv[10] = -ORBInitRef
argv[11] = NameService=corbaloc::albert:3500/NameService
Initialize orb
Call run
get reference to initial naming context
narrow name context
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 130.127.112.116:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 130.127.226.19:3892
  remote address: 130.127.112.116:3500 ]
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 130.127.226.19:3892
  remote address: 130.127.112.116:3500 ]
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 130.127.112.116:3500 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 130.127.226.19:3893
  remote address: 130.127.112.116:3500 ]
initialize the name of our object to look for to MyFFN
resolve name
resolve new context
narrow to NeuralNetFactory
******************************************
use NeuralNetfactory reference to 
create a FFN Object:
[ outgoing: trying to establish connection
  timeout: none
  id: TAG_IIOP
  remote address: 130.127.112.116:5000 ]
[ outgoing: new connection
  id: TAG_IIOP
  local address: 130.127.226.19:3894
  remote address: 130.127.112.116:5000 ]
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 130.127.226.19:3893
  remote address: 130.127.112.116:3500 ]
[ outgoing: closing connection
  id: TAG_IIOP
  local address: 130.127.226.19:3894
  remote address: 130.127.112.116:5000 ]


Now the output from the FFN program shows up on albert:
albert% [ incoming: new connection
  id: TAG_IIOP
  local address: 130.127.112.116:5000
  remote address: 130.127.226.19:3894 ]
NeuralNetsFactory:: create a FFN Object
create NeuralNets::FFN_impl *FFNimpl
   = new NeuralNets::FFN_impl(poa_)
return FFN object
  call return FFNimpl->_this();
.
.
.
usual FFN output as we have seen before
.
.
.
 writing synaptic weights to file
[ incoming: closing connection
  id: TAG_IIOP
  local address: 130.127.112.116:5000
  remote address: 130.127.226.19:3894 ]

Previous Contents Next