xref: /petsc/src/sys/classes/viewer/impls/socket/send.c (revision cad6c63bf8b7a4d502ce4b180922248c097848ad)
1 
2 #include <petscsys.h>
3 
4 #if defined(PETSC_NEEDS_UTYPE_TYPEDEFS)
5 /* Some systems have inconsistent include files that use but do not
6    ensure that the following definitions are made */
7 typedef unsigned char   u_char;
8 typedef unsigned short  u_short;
9 typedef unsigned short  ushort;
10 typedef unsigned int    u_int;
11 typedef unsigned long   u_long;
12 #endif
13 
14 #include <errno.h>
15 #include <ctype.h>
16 #if defined(PETSC_HAVE_MACHINE_ENDIAN_H)
17 #include <machine/endian.h>
18 #endif
19 #if defined(PETSC_HAVE_UNISTD_H)
20 #include <unistd.h>
21 #endif
22 #if defined(PETSC_HAVE_SYS_SOCKET_H)
23 #include <sys/socket.h>
24 #endif
25 #if defined(PETSC_HAVE_SYS_WAIT_H)
26 #include <sys/wait.h>
27 #endif
28 #if defined(PETSC_HAVE_NETINET_IN_H)
29 #include <netinet/in.h>
30 #endif
31 #if defined(PETSC_HAVE_NETDB_H)
32 #include <netdb.h>
33 #endif
34 #if defined(PETSC_HAVE_FCNTL_H)
35 #include <fcntl.h>
36 #endif
37 #if defined(PETSC_HAVE_IO_H)
38 #include <io.h>
39 #endif
40 #if defined(PETSC_HAVE_WINSOCK2_H)
41 #include <Winsock2.h>
42 #endif
43 #include <sys/stat.h>
44 #include <../src/sys/classes/viewer/impls/socket/socket.h>
45 
46 #if defined(PETSC_NEED_CLOSE_PROTO)
47 PETSC_EXTERN int close(int);
48 #endif
49 #if defined(PETSC_NEED_SOCKET_PROTO)
50 PETSC_EXTERN int socket(int,int,int);
51 #endif
52 #if defined(PETSC_NEED_SLEEP_PROTO)
53 PETSC_EXTERN int sleep(unsigned);
54 #endif
55 #if defined(PETSC_NEED_CONNECT_PROTO)
56 PETSC_EXTERN int connect(int,struct sockaddr*,int);
57 #endif
58 
59 /*--------------------------------------------------------------*/
60 #undef __FUNCT__
61 #define __FUNCT__ "PetscViewerDestroy_Socket"
62 static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
63 {
64   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)viewer->data;
65   PetscErrorCode     ierr;
66 
67   PetscFunctionBegin;
68   if (vmatlab->port) {
69 #if defined(PETSC_HAVE_CLOSESOCKET)
70     ierr = closesocket(vmatlab->port);
71 #else
72     ierr = close(vmatlab->port);
73 #endif
74     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"System error closing socket");
75   }
76   ierr = PetscFree(vmatlab);CHKERRQ(ierr);
77   PetscFunctionReturn(0);
78 }
79 
80 /*--------------------------------------------------------------*/
81 #undef __FUNCT__
82 #define __FUNCT__ "PetscOpenSocket"
83 /*
84     PetscSocketOpen - handles connected to an open port where someone is waiting.
85 
86 .seealso:   PetscSocketListen(), PetscSocketEstablish()
87 */
88 PetscErrorCode  PetscOpenSocket(char *hostname,int portnum,int *t)
89 {
90   struct sockaddr_in sa;
91   struct hostent     *hp;
92   int                s = 0;
93   PetscErrorCode     ierr;
94   PetscBool          flg = PETSC_TRUE;
95 
96   PetscFunctionBegin;
97   if (!(hp=gethostbyname(hostname))) {
98     perror("SEND: error gethostbyname: ");
99     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error open connection to %s",hostname);
100   }
101   ierr = PetscMemzero(&sa,sizeof(sa));CHKERRQ(ierr);
102   ierr = PetscMemcpy(&sa.sin_addr,hp->h_addr_list[0],hp->h_length);CHKERRQ(ierr);
103 
104   sa.sin_family = hp->h_addrtype;
105   sa.sin_port   = htons((u_short) portnum);
106   while (flg) {
107     if ((s=socket(hp->h_addrtype,SOCK_STREAM,0)) < 0) {
108       perror("SEND: error socket");  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
109     }
110     if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
111 #if defined(PETSC_HAVE_WSAGETLASTERROR)
112       ierr = WSAGetLastError();
113       if (ierr == WSAEADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
114       else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
115       else if (ierr == WSAEISCONN) {
116         (*PetscErrorPrintf)("SEND: socket already connected\n");
117         Sleep((unsigned) 1);
118       } else if (ierr == WSAECONNREFUSED) {
119         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
120         Sleep((unsigned) 1);
121       } else {
122         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
123       }
124 #else
125       if (errno == EADDRINUSE)    (*PetscErrorPrintf)("SEND: address is in use\n");
126       else if (errno == EALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
127       else if (errno == EISCONN) {
128         (*PetscErrorPrintf)("SEND: socket already connected\n");
129         sleep((unsigned) 1);
130       } else if (errno == ECONNREFUSED) {
131         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
132         ierr = PetscInfo(0,"Connection refused in attaching socket, trying again");CHKERRQ(ierr);
133         sleep((unsigned) 1);
134       } else {
135         perror(NULL); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"system error");
136       }
137 #endif
138       flg = PETSC_TRUE;
139 #if defined(PETSC_HAVE_CLOSESOCKET)
140       closesocket(s);
141 #else
142       close(s);
143 #endif
144     } else flg = PETSC_FALSE;
145   }
146   *t = s;
147   PetscFunctionReturn(0);
148 }
149 
150 #define MAXHOSTNAME 100
151 #undef __FUNCT__
152 #define __FUNCT__ "PetscSocketEstablish"
153 /*
154    PetscSocketEstablish - starts a listener on a socket
155 
156 .seealso:   PetscSocketListen()
157 */
158 PetscErrorCode PetscSocketEstablish(int portnum,int *ss)
159 {
160   char               myname[MAXHOSTNAME+1];
161   int                s;
162   PetscErrorCode     ierr;
163   struct sockaddr_in sa;
164   struct hostent     *hp;
165 
166   PetscFunctionBegin;
167   ierr = PetscGetHostName(myname,MAXHOSTNAME);CHKERRQ(ierr);
168 
169   ierr = PetscMemzero(&sa,sizeof(struct sockaddr_in));CHKERRQ(ierr);
170 
171   hp = gethostbyname(myname);
172   if (!hp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Unable to get hostent information from system");
173 
174   sa.sin_family = hp->h_addrtype;
175   sa.sin_port   = htons((u_short)portnum);
176 
177   if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error running socket() command");
178 #if defined(PETSC_HAVE_SO_REUSEADDR)
179   {
180     int optval = 1; /* Turn on the option */
181     ierr = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&optval,sizeof(optval));CHKERRQ(ierr);
182   }
183 #endif
184 
185   while (bind(s,(struct sockaddr*)&sa,sizeof(sa)) < 0) {
186 #if defined(PETSC_HAVE_WSAGETLASTERROR)
187     ierr = WSAGetLastError();
188     if (ierr != WSAEADDRINUSE) {
189 #else
190     if (errno != EADDRINUSE) {
191 #endif
192       close(s);
193       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"Error from bind()");
194     }
195   }
196   listen(s,0);
197   *ss = s;
198   return(0);
199 }
200 
201 #undef __FUNCT__
202 #define __FUNCT__ "PetscSocketListen"
203 /*
204    PetscSocketListens - Listens at a socket created with PetscSocketEstablish()
205 
206 .seealso:   PetscSocketEstablish()
207 */
208 PetscErrorCode PetscSocketListen(int listenport,int *t)
209 {
210   struct sockaddr_in isa;
211 #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
212   size_t             i;
213 #else
214   int                i;
215 #endif
216 
217   PetscFunctionBegin;
218   /* wait for someone to try to connect */
219   i = sizeof(struct sockaddr_in);
220   if ((*t = accept(listenport,(struct sockaddr*)&isa,(socklen_t*)&i)) < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"error from accept()\n");
221   PetscFunctionReturn(0);
222 }
223 
224 #undef __FUNCT__
225 #define __FUNCT__ "PetscViewerSocketOpen"
226 /*@C
227    PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket
228         based server.
229 
230    Collective on MPI_Comm
231 
232    Input Parameters:
233 +  comm - the MPI communicator
234 .  machine - the machine the server is running on,, use NULL for the local machine, use "server" to passively wait for
235              a connection from elsewhere
236 -  port - the port to connect to, use PETSC_DEFAULT for the default
237 
238    Output Parameter:
239 .  lab - a context to use when communicating with the server
240 
241    Level: intermediate
242 
243    Notes:
244    Most users should employ the following commands to access the
245    MATLAB PetscViewers
246 $
247 $    PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
248 $    MatView(Mat matrix,PetscViewer viewer)
249 $
250 $                or
251 $
252 $    PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
253 $    VecView(Vec vector,PetscViewer viewer)
254 
255    Options Database Keys:
256    For use with  PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF,
257    PETSC_VIEWER_SOCKET_() or if
258     NULL is passed for machine or PETSC_DEFAULT is passed for port
259 $    -viewer_socket_machine <machine>
260 $    -viewer_socket_port <port>
261 
262    Environmental variables:
263 +   PETSC_VIEWER_SOCKET_PORT portnumber
264 -   PETSC_VIEWER_SOCKET_MACHINE machine name
265 
266      Currently the only socket client available is MATLAB. See
267      src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage.
268 
269    Notes: The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
270           use PetscViewerBinaryRead/Write/GetDescriptor().
271 
272    Concepts: MATLAB^sending data
273    Concepts: sockets^sending data
274 
275 .seealso: MatView(), VecView(), PetscViewerDestroy(), PetscViewerCreate(), PetscViewerSetType(),
276           PetscViewerSocketSetConnection(), PETSC_VIEWER_SOCKET_, PETSC_VIEWER_SOCKET_WORLD,
277           PETSC_VIEWER_SOCKET_SELF, PetscViewerBinaryWrite(), PetscViewerBinaryRead(), PetscViewerBinaryWriteStringArray(),
278           PetscBinaryViewerGetDescriptor()
279 @*/
280 PetscErrorCode  PetscViewerSocketOpen(MPI_Comm comm,const char machine[],int port,PetscViewer *lab)
281 {
282   PetscErrorCode ierr;
283 
284   PetscFunctionBegin;
285   ierr = PetscViewerCreate(comm,lab);CHKERRQ(ierr);
286   ierr = PetscViewerSetType(*lab,PETSCVIEWERSOCKET);CHKERRQ(ierr);
287   ierr = PetscViewerSocketSetConnection(*lab,machine,port);CHKERRQ(ierr);
288   PetscFunctionReturn(0);
289 }
290 
291 #undef __FUNCT__
292 #define __FUNCT__ "PetscViewerSetFromOptions_Socket"
293 static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v)
294 {
295   PetscErrorCode ierr;
296   PetscInt       def = -1;
297   char           sdef[256];
298   PetscBool      tflg;
299 
300   PetscFunctionBegin;
301   /*
302        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
303     are listed here for the GUI to display
304   */
305   ierr = PetscOptionsHead("Socket PetscViewer Options");CHKERRQ(ierr);
306   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",sdef,16,&tflg);CHKERRQ(ierr);
307   if (tflg) {
308     ierr = PetscOptionsStringToInt(sdef,&def);CHKERRQ(ierr);
309   } else def = PETSCSOCKETDEFAULTPORT;
310   ierr = PetscOptionsInt("-viewer_socket_port","Port number to use for socket","PetscViewerSocketSetConnection",def,0,0);CHKERRQ(ierr);
311 
312   ierr = PetscOptionsString("-viewer_socket_machine","Machine to use for socket","PetscViewerSocketSetConnection",sdef,0,0,0);CHKERRQ(ierr);
313   ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",sdef,256,&tflg);CHKERRQ(ierr);
314   if (!tflg) {
315     ierr = PetscGetHostName(sdef,256);CHKERRQ(ierr);
316   }
317   ierr = PetscOptionsTail();CHKERRQ(ierr);
318   PetscFunctionReturn(0);
319 }
320 
321 #undef __FUNCT__
322 #define __FUNCT__ "PetscViewerCreate_Socket"
323 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
324 {
325   PetscViewer_Socket *vmatlab;
326   PetscErrorCode     ierr;
327 
328   PetscFunctionBegin;
329   ierr                   = PetscNewLog(v,PetscViewer_Socket,&vmatlab);CHKERRQ(ierr);
330   vmatlab->port          = 0;
331   v->data                = (void*)vmatlab;
332   v->ops->destroy        = PetscViewerDestroy_Socket;
333   v->ops->flush          = 0;
334   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;
335 
336   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
337   ierr                   = PetscObjectChangeTypeName((PetscObject)v,PETSCVIEWERBINARY);CHKERRQ(ierr);
338   PetscFunctionReturn(0);
339 }
340 
341 #undef __FUNCT__
342 #define __FUNCT__ "PetscViewerSocketSetConnection"
343 /*@C
344       PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
345              viewer is to use
346 
347   Logically Collective on PetscViewer
348 
349   Input Parameters:
350 +   v - viewer to connect
351 .   machine - host to connect to, use NULL for the local machine,use "server" to passively wait for
352              a connection from elsewhere
353 -   port - the port on the machine one is connecting to, use PETSC_DEFAULT for default
354 
355     Level: advanced
356 
357 .seealso: PetscViewerSocketOpen()
358 @*/
359 PetscErrorCode  PetscViewerSocketSetConnection(PetscViewer v,const char machine[],int port)
360 {
361   PetscErrorCode     ierr;
362   PetscMPIInt        rank;
363   char               mach[256];
364   PetscBool          tflg;
365   PetscViewer_Socket *vmatlab = (PetscViewer_Socket*)v->data;
366 
367   PetscFunctionBegin;
368   /* PetscValidLogicalCollectiveInt(v,port,3); not a PetscInt */
369   if (port <= 0) {
370     char portn[16];
371     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_PORT",portn,16,&tflg);CHKERRQ(ierr);
372     if (tflg) {
373       PetscInt pport;
374       ierr = PetscOptionsStringToInt(portn,&pport);CHKERRQ(ierr);
375       port = (int)pport;
376     } else port = PETSCSOCKETDEFAULTPORT;
377   }
378   if (!machine) {
379     ierr = PetscOptionsGetenv(PetscObjectComm((PetscObject)v),"PETSC_VIEWER_SOCKET_MACHINE",mach,256,&tflg);CHKERRQ(ierr);
380     if (!tflg) {
381       ierr = PetscGetHostName(mach,256);CHKERRQ(ierr);
382     }
383   } else {
384     ierr = PetscStrncpy(mach,machine,256);CHKERRQ(ierr);
385   }
386 
387   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)v),&rank);CHKERRQ(ierr);
388   if (!rank) {
389     ierr = PetscStrcmp(mach,"server",&tflg);CHKERRQ(ierr);
390     if (tflg) {
391       int listenport;
392       ierr = PetscInfo1(v,"Waiting for connection from socket process on port %D\n",port);CHKERRQ(ierr);
393       ierr = PetscSocketEstablish(port,&listenport);CHKERRQ(ierr);
394       ierr = PetscSocketListen(listenport,&vmatlab->port);CHKERRQ(ierr);
395       close(listenport);
396     } else {
397       ierr = PetscInfo2(v,"Connecting to socket process on port %D machine %s\n",port,mach);CHKERRQ(ierr);
398       ierr = PetscOpenSocket(mach,port,&vmatlab->port);CHKERRQ(ierr);
399     }
400   }
401   PetscFunctionReturn(0);
402 }
403 
404 /* ---------------------------------------------------------------------*/
405 /*
406     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
407   is attached to a communicator, in this case the attribute is a PetscViewer.
408 */
409 static PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;
410 
411 
412 #undef __FUNCT__
413 #define __FUNCT__ "PETSC_VIEWER_SOCKET_"
414 /*@C
415      PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.
416 
417      Collective on MPI_Comm
418 
419      Input Parameter:
420 .    comm - the MPI communicator to share the socket PetscViewer
421 
422      Level: intermediate
423 
424    Options Database Keys:
425    For use with the default PETSC_VIEWER_SOCKET_WORLD or if
426     NULL is passed for machine or PETSC_DEFAULT is passed for port
427 $    -viewer_socket_machine <machine>
428 $    -viewer_socket_port <port>
429 
430    Environmental variables:
431 +   PETSC_VIEWER_SOCKET_PORT portnumber
432 -   PETSC_VIEWER_SOCKET_MACHINE machine name
433 
434      Notes:
435      Unlike almost all other PETSc routines, PetscViewer_SOCKET_ does not return
436      an error code.  The socket PetscViewer is usually used in the form
437 $       XXXView(XXX object,PETSC_VIEWER_SOCKET_(comm));
438 
439      Currently the only socket client available is MATLAB. See
440      src/dm/da/examples/tests/ex12.c and ex12.m for an example of usage.
441 
442      Connects to a waiting socket and stays connected until PetscViewerDestroy() is called.
443 
444      Use this for communicating with an interactive MATLAB session, see PETSC_VIEWER_MATLAB_() for communicating with the MATLAB engine.
445 
446 .seealso: PETSC_VIEWER_SOCKET_WORLD, PETSC_VIEWER_SOCKET_SELF, PetscViewerSocketOpen(), PetscViewerCreate(),
447           PetscViewerSocketSetConnection(), PetscViewerDestroy(), PETSC_VIEWER_SOCKET_(), PetscViewerBinaryWrite(), PetscViewerBinaryRead(),
448           PetscViewerBinaryWriteStringArray(), PetscBinaryViewerGetDescriptor(), PETSC_VIEWER_MATLAB_()
449 @*/
450 PetscViewer  PETSC_VIEWER_SOCKET_(MPI_Comm comm)
451 {
452   PetscErrorCode ierr;
453   PetscBool      flg;
454   PetscViewer    viewer;
455   MPI_Comm       ncomm;
456 
457   PetscFunctionBegin;
458   ierr = PetscCommDuplicate(comm,&ncomm,NULL);if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
459   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) {
460     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Viewer_Socket_keyval,0);
461     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
462   }
463   ierr = MPI_Attr_get(ncomm,Petsc_Viewer_Socket_keyval,(void**)&viewer,(int*)&flg);
464   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
465   if (!flg) { /* PetscViewer not yet created */
466     ierr = PetscViewerSocketOpen(ncomm,0,0,&viewer);
467     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
468     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
469     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
470     ierr = MPI_Attr_put(ncomm,Petsc_Viewer_Socket_keyval,(void*)viewer);
471     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
472   }
473   ierr = PetscCommDestroy(&ncomm);
474   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_SOCKET_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
475   PetscFunctionReturn(viewer);
476 }
477 
478 /* ---------------------------------------------------------------------*/
479 #if defined(PETSC_USE_SERVER)
480 
481 #include <pthread.h>
482 #include <time.h>
483 #define PROTOCOL   "HTTP/1.1"
484 #define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"
485 
486 #undef __FUNCT__
487 #define __FUNCT__ "PetscWebSendHeader"
488 PetscErrorCode PetscWebSendHeader(FILE *f, int status, const char *title, const char *extra, const char *mime, int length)
489 {
490   time_t now;
491   char   timebuf[128];
492 
493   PetscFunctionBegin;
494   fprintf(f, "%s %d %s\r\n", PROTOCOL, status, title);
495   fprintf(f, "Server: %s\r\n", "petscserver/1.0");
496   now = time(NULL);
497   strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
498   fprintf(f, "Date: %s\r\n", timebuf);
499   if (extra) fprintf(f, "%s\r\n", extra);
500   if (mime) fprintf(f, "Content-Type: %s\r\n", mime);
501   if (length >= 0) fprintf(f, "Content-Length: %d\r\n", length);
502   fprintf(f, "Connection: close\r\n");
503   fprintf(f, "\r\n");
504   PetscFunctionReturn(0);
505 }
506 
507 #undef __FUNCT__
508 #define __FUNCT__ "PetscWebSendFooter"
509 PetscErrorCode PetscWebSendFooter(FILE *fd)
510 {
511   PetscFunctionBegin;
512   fprintf(fd, "</BODY></HTML>\r\n");
513   PetscFunctionReturn(0);
514 }
515 
516 #undef __FUNCT__
517 #define __FUNCT__ "PetscWebSendError"
518 PetscErrorCode PetscWebSendError(FILE *f, int status, const char *title, const char *extra, const char *text)
519 {
520   PetscErrorCode ierr;
521 
522   PetscFunctionBegin;
523   ierr = PetscWebSendHeader(f, status, title, extra, "text/html", -1);CHKERRQ(ierr);
524   fprintf(f, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
525   fprintf(f, "<BODY><H4>%d %s</H4>\r\n", status, title);
526   fprintf(f, "%s\r\n", text);
527   ierr = PetscWebSendFooter(f);CHKERRQ(ierr);
528   PetscFunctionReturn(0);
529 }
530 
531 #if defined(PETSC_HAVE_AMS)
532 #undef __FUNCT__
533 #define __FUNCT__ "PetscAMSObjectsDisplayList"
534 /*
535     Displays all the PETSc objects published with AMS in a simple HTML list
536 
537     Does NOT use Javascript or JSON-RPC
538 */
539 static PetscErrorCode PetscAMSObjectsDisplayList(FILE *fd)
540 {
541   PetscErrorCode     ierr;
542   char               host[256],**comm_list,**mem_list,**fld_list;
543   AMS_Comm           ams;
544   PetscInt           i = 0,j;
545   AMS_Memory_type    mtype;
546   AMS_Data_type      dtype;
547   AMS_Shared_type    stype;
548   AMS_Reduction_type rtype;
549   AMS_Memory         memory;
550   int                len;
551   void               *addr;
552 
553   ierr = PetscGetHostName(host,256);CHKERRQ(ierr);
554   ierr = AMS_Connect(host, -1, &comm_list);CHKERRQ(ierr);
555   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
556   if (!comm_list || !comm_list[0]) fprintf(fd, "AMS Communicator not running</p>\r\n");
557   else {
558     ierr = AMS_Comm_attach(comm_list[0],&ams);CHKERRQ(ierr);
559     ierr = AMS_Comm_get_memory_list(ams,&mem_list);CHKERRQ(ierr);
560     if (!mem_list[0]) fprintf(fd, "AMS Communicator %s has no published memories</p>\r\n",comm_list[0]);
561     else {
562       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE></HEAD>\r\n<BODY>");
563       fprintf(fd,"<ul>\r\n");
564       while (mem_list[i]) {
565         fprintf(fd,"<li> %s</li>\r\n",mem_list[i]);
566         ierr = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
567         ierr = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
568         j    = 0;
569         fprintf(fd,"<ul>\r\n");
570         while (fld_list[j]) {
571           fprintf(fd,"<li> %s",fld_list[j]);
572           ierr = AMS_Memory_get_field_info(memory, fld_list[j], &addr, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
573           if (len == 1) {
574             if (dtype == AMS_INT)         fprintf(fd," %d",*(int*)addr);
575             else if (dtype == AMS_STRING) fprintf(fd," %s",*(char**)addr);
576           }
577           fprintf(fd,"</li>\r\n");
578           j++;
579         }
580         fprintf(fd,"</ul>\r\n");
581         i++;
582       }
583       fprintf(fd,"</ul>\r\n");
584     }
585   }
586   ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
587   ierr = AMS_Disconnect();CHKERRQ(ierr);
588   PetscFunctionReturn(0);
589 }
590 
591 #undef __FUNCT__
592 #define __FUNCT__ "PetscAMSObjectsDisplayTree"
593 /*
594     Displays all the PETSc objects published with AMS in very crude HTML 5 graphics
595 
596     Does NOT use Javascript or JSON-RPC
597 */
598 static PetscErrorCode PetscAMSObjectsDisplayTree(FILE *fd)
599 {
600   PetscErrorCode     ierr;
601   char               host[256],**comm_list,**mem_list,**fld_list;
602   AMS_Comm           ams;
603   PetscInt           i = 0,j;
604   AMS_Memory_type    mtype;
605   AMS_Data_type      dtype;
606   AMS_Shared_type    stype;
607   AMS_Reduction_type rtype;
608   AMS_Memory         memory;
609   int                len;
610   void               *addr2,*addr3,*addr,*addr4;
611 
612   ierr = PetscGetHostName(host,256);CHKERRQ(ierr);
613   ierr = AMS_Connect(host, -1, &comm_list);CHKERRQ(ierr);
614   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
615   if (!comm_list || !comm_list[0]) fprintf(fd, "AMS Communicator not running</p>\r\n");
616   else {
617     ierr = AMS_Comm_attach(comm_list[0],&ams);CHKERRQ(ierr);
618     ierr = AMS_Comm_get_memory_list(ams,&mem_list);CHKERRQ(ierr);
619     if (!mem_list[0]) fprintf(fd, "AMS Communicator %s has no published memories</p>\r\n",comm_list[0]);
620     else {
621       PetscInt  Nlevels,*Level,*Levelcnt,*Idbylevel,*Column,*parentid,*Id,maxId = 0,maxCol = 0,*parentId,id,cnt,Nlevelcnt = 0;
622       PetscBool *mask;
623       char      **classes,*clas,**subclasses,*sclas;
624 
625       /* get maximum number of objects */
626       while (mem_list[i]) {
627         ierr  = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
628         ierr  = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
629         ierr  = AMS_Memory_get_field_info(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
630         Id    = (int*) addr2;
631         maxId = PetscMax(maxId,*Id);
632         i++;
633       }
634       maxId++;
635 
636       /* Gets everyone's parent ID and which nodes are masked */
637       ierr = PetscMalloc4(maxId,PetscInt,&parentid,maxId,PetscBool,&mask,maxId,char**,&classes,maxId,char**,&subclasses);CHKERRQ(ierr);
638       ierr = PetscMemzero(classes,maxId*sizeof(char*));CHKERRQ(ierr);
639       ierr = PetscMemzero(subclasses,maxId*sizeof(char*));CHKERRQ(ierr);
640       for (i=0; i<maxId; i++) mask[i] = PETSC_TRUE;
641       i = 0;
642       while (mem_list[i]) {
643         ierr          = AMS_Memory_attach(ams,mem_list[i],&memory,NULL);CHKERRQ(ierr);
644         ierr          = AMS_Memory_get_field_list(memory, &fld_list);CHKERRQ(ierr);
645         ierr          = AMS_Memory_get_field_info(memory, "Id", &addr2, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
646         Id            = (int*) addr2;
647         ierr          = AMS_Memory_get_field_info(memory, "ParentId", &addr3, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
648         parentId      = (int*) addr3;
649         ierr          = AMS_Memory_get_field_info(memory, "Class", &addr, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
650         clas          = *(char**)addr;
651         ierr          = AMS_Memory_get_field_info(memory, "Type", &addr4, &len, &dtype, &mtype, &stype, &rtype);CHKERRQ(ierr);
652         sclas         = *(char**)addr4;
653         parentid[*Id] = *parentId;
654         mask[*Id]     = PETSC_FALSE;
655 
656         ierr = PetscStrallocpy(clas,classes+*Id);CHKERRQ(ierr);
657         ierr = PetscStrallocpy(sclas,subclasses+*Id);CHKERRQ(ierr);
658         i++;
659       }
660 
661       /* if the parent is masked then relabel the parent as 0 since the true parent was deleted */
662       for (i=0; i<maxId; i++) {
663         if (!mask[i] && parentid[i] > 0 && mask[parentid[i]]) parentid[i] = 0;
664       }
665 
666       ierr = PetscProcessTree(maxId,mask,parentid,&Nlevels,&Level,&Levelcnt,&Idbylevel,&Column);CHKERRQ(ierr);
667 
668       for (i=0; i<Nlevels; i++) maxCol    = PetscMax(maxCol,Levelcnt[i]);
669       for (i=0; i<Nlevels; i++) Nlevelcnt = PetscMax(Nlevelcnt,Levelcnt[i]);
670 
671       /* print all the top-level objects */
672       fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE>\r\n");
673       fprintf(fd, "<canvas width=800 height=600 id=\"tree\"></canvas>\r\n");
674       fprintf(fd, "<script type=\"text/javascript\">\r\n");
675       fprintf(fd, "  function draw() {\r\n");
676       fprintf(fd, "  var example = document.getElementById('tree');\r\n");
677       fprintf(fd, "  var context = example.getContext('2d');\r\n");
678       /* adjust font size based on how big a tree is printed */
679       if (Nlevels > 5 || Nlevelcnt > 10) fprintf(fd, "  context.font         = \"normal 12px sans-serif\";\r\n");
680       else                               fprintf(fd, "  context.font         = \"normal 24px sans-serif\";\r\n");
681       fprintf(fd, "  context.fillStyle = \"rgb(255,0,0)\";\r\n");
682       fprintf(fd, "  context.textBaseline = \"top\";\r\n");
683       fprintf(fd, "  var xspacep = 0;\r\n");
684       fprintf(fd, "  var yspace = example.height/%d;\r\n",(Nlevels+1));
685       /* estimate the height of a string as twice the width of a character */
686       fprintf(fd, "  var wheight = context.measureText(\"K\");\r\n");
687       fprintf(fd, "  var height = 1.6*wheight.width;\r\n");
688 
689       cnt = 0;
690       for (i=0; i<Nlevels; i++) {
691         fprintf(fd, "  var xspace = example.width/%d;\r\n",Levelcnt[i]+1);
692         for (j=0; j<Levelcnt[i]; j++) {
693           id    = Idbylevel[cnt++];
694           clas  = classes[id];
695           sclas = subclasses[id];
696           fprintf(fd, "  var width = context.measureText(\"%s\");\r\n",clas);
697           fprintf(fd, "  var swidth = context.measureText(\"%s\");\r\n",sclas);
698           fprintf(fd, "  context.fillStyle = \"rgb(255,0,0)\";\r\n");
699           fprintf(fd, "  context.fillRect((%d)*xspace-width.width/2, %d*yspace-height/2, width.width, height);\r\n",j+1,i+1);
700           fprintf(fd, "  context.fillRect((%d)*xspace-swidth.width/2, %d*yspace+height/2, swidth.width, height);\r\n",j+1,i+1);
701           fprintf(fd, "  context.fillStyle = \"rgb(0,0,0)\";\r\n");
702           fprintf(fd, "  context.fillText(\"%s\",(%d)*xspace-width.width/2, %d*yspace-height/2);\r\n",clas,j+1,i+1);
703           fprintf(fd, "  context.fillText(\"%s\",(%d)*xspace-swidth.width/2, %d*yspace+height/2);\r\n",sclas,j+1,i+1);
704           if (parentid[id]) {
705             fprintf(fd, "  context.moveTo(%d*xspace,%d*yspace-height/2);\r\n",j+1,i+1);
706             fprintf(fd, "  context.lineTo(%d*xspacep,%d*yspace+3*height/2);\r\n",Column[parentid[id]]+1,i);
707             fprintf(fd, "  context.stroke();\r\n");
708           }
709         }
710         fprintf(fd, "  xspacep = xspace;\r\n");
711       }
712       ierr = PetscFree(Level);CHKERRQ(ierr);
713       ierr = PetscFree(Levelcnt);CHKERRQ(ierr);
714       ierr = PetscFree(Idbylevel);CHKERRQ(ierr);
715       ierr = PetscFree(Column);CHKERRQ(ierr);
716       for (i=0; i<maxId; i++) {
717         ierr = PetscFree(classes[i]);CHKERRQ(ierr);
718         ierr = PetscFree(subclasses[i]);CHKERRQ(ierr);
719       }
720       ierr = PetscFree4(mask,parentid,classes,subclasses);CHKERRQ(ierr);
721 
722       ierr = AMS_Disconnect();CHKERRQ(ierr);
723       fprintf(fd, "}\r\n");
724       fprintf(fd, "</script>\r\n");
725       fprintf(fd, "<body onload=\"draw();\">\r\n");
726       fprintf(fd, "</body></html>\r\n");
727     }
728   }
729   ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
730   PetscFunctionReturn(0);
731 }
732 #endif
733 
734 #undef __FUNCT__
735 #define __FUNCT__ "PetscWebServeRequestGet"
736 /*@C
737       PetscWebServeRequestGet - serves a single web Get request
738 
739     Not collective
740 
741   Input Parameters:
742 +   port - the network file to read and write from
743 -   path - the command from the server
744 
745     Level: developer
746 
747 .seealso: PetscWebServe()
748 @*/
749 static PetscErrorCode  PetscWebServeRequestGet(FILE *fd,const char path[])
750 {
751   PetscErrorCode ierr;
752   FILE           *fdo;
753   char           fullpath[PETSC_MAX_PATH_LEN],truefullpath[PETSC_MAX_PATH_LEN];
754   const char     *type;
755   PetscBool      flg;
756 
757   PetscFunctionBegin;
758   fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
759 
760   ierr = PetscStrcmp(path,"/favicon.ico",&flg);CHKERRQ(ierr);
761   if (flg) {
762     /* should have cool PETSc icon */;
763     PetscFunctionReturn(0);
764   }
765   ierr = PetscStrcmp(path,"/",&flg);CHKERRQ(ierr);
766   if (flg) {
767     char        program[128];
768     PetscMPIInt size;
769     PetscViewer viewer;
770 
771     ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);
772     ierr = PetscGetProgramName(program,128);CHKERRQ(ierr);
773     ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "text/html", -1);CHKERRQ(ierr);
774     fprintf(fd, "<HTML><HEAD><TITLE>Petsc Application Server</TITLE></HEAD>\r\n<BODY>");
775     fprintf(fd, "<H4>Serving PETSc application code %s </H4>\r\n\n",program);
776     fprintf(fd, "Number of processes %d\r\n\n",size);
777     fprintf(fd, "<HR>\r\n");
778     ierr = PetscViewerASCIIOpenWithFILE(PETSC_COMM_WORLD,fd,&viewer);CHKERRQ(ierr);
779     ierr = PetscOptionsView(viewer);CHKERRQ(ierr);
780     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
781     fprintf(fd, "<HR>\r\n");
782 #if defined(PETSC_HAVE_AMS)
783     if (PetscAMSPublishAll) {
784       fprintf(fd, "<a href=\"./ams-tree\">Connect to Memory Snooper--Tree Display</a></p>\r\n\r\n");
785       fprintf(fd, "<a href=\"./ams-list\">Connect to Memory Snooper--List Display</a></p>\r\n\r\n");
786     }
787 #endif
788     fprintf(fd, "<a href=\"./AMSJavascript.html\">Connect to Memory Snooper--Interactive Javascript</a></p>\r\n\r\n");
789     ierr = PetscWebSendFooter(fd);CHKERRQ(ierr);
790     PetscFunctionReturn(0);
791   }
792 
793 #if defined(PETSC_HAVE_AMS)
794   ierr = PetscStrcmp(path,"/ams-list",&flg);CHKERRQ(ierr);
795   if (flg) {
796     ierr = PetscAMSObjectsDisplayList(fd);CHKERRQ(ierr);
797     PetscFunctionReturn(0);
798   }
799   ierr = PetscStrcmp(path,"/ams-tree",&flg);CHKERRQ(ierr);
800   if (flg) {
801     ierr = PetscAMSObjectsDisplayTree(fd);CHKERRQ(ierr);
802     PetscFunctionReturn(0);
803   }
804 #endif
805   ierr = PetscStrcpy(fullpath,"${PETSC_DIR}/include/web");CHKERRQ(ierr);
806   ierr = PetscStrcat(fullpath,path);CHKERRQ(ierr);
807   ierr = PetscInfo1(NULL,"Checking for file %s\n",fullpath);CHKERRQ(ierr);
808   ierr = PetscStrreplace(PETSC_COMM_SELF,fullpath,truefullpath,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
809   fdo  = fopen(truefullpath,"r");
810   if (fdo) {
811     PetscInt    length,index;
812     char        data[4096];
813     struct stat statbuf;
814     int         n;
815     const char  *suffixes[] = {".html",".js",".gif",0}, *mimes[] = {"text/html","text/javascript","image/gif","text/unknown"};
816 
817     ierr = PetscStrendswithwhich(fullpath,suffixes,&index);CHKERRQ(ierr);
818     type = mimes[index];
819     if (!stat(truefullpath, &statbuf)) length = -1;
820     else length = S_ISREG(statbuf.st_mode) ? statbuf.st_size : -1;
821     ierr = PetscWebSendHeader(fd, 200, "OK", NULL, type, length);CHKERRQ(ierr);
822     while ((n = fread(data, 1, sizeof(data), fdo)) > 0) fwrite(data, 1, n, fd);
823     fclose(fdo);
824     ierr = PetscInfo2(NULL,"Sent file %s to browser using format %s\n",fullpath,type);CHKERRQ(ierr);
825     PetscFunctionReturn(0);
826   }
827   ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Unknown request.");CHKERRQ(ierr);
828   PetscFunctionReturn(0);
829 }
830 
831 #if defined(PETSC_HAVE_YAML)
832 
833 /*
834     Toy YAML/JSON-RPC function that returns all the arguments it is passed
835 */
836 #undef __FUNCT__
837 #define __FUNCT__ "YAML_echo"
838 PETSC_UNUSED static PetscErrorCode YAML_echo(PetscInt argc,char **args,PetscInt *argco,char ***argso)
839 {
840   PetscErrorCode ierr;
841   PetscInt       i;
842 
843   ierr = PetscPrintf(PETSC_COMM_SELF,"Number of arguments to function %d\n",argc);CHKERRQ(ierr);
844   for (i=0; i<argc; i++) {
845     ierr = PetscPrintf(PETSC_COMM_SELF,"  %s\n",args[i]);CHKERRQ(ierr);
846   }
847   *argco = argc;
848   ierr   = PetscMalloc(argc*sizeof(char*),argso);CHKERRQ(ierr);
849   for (i=0; i<argc; i++) {
850     ierr = PetscStrallocpy(args[i],&(*argso)[i]);CHKERRQ(ierr);
851   }
852   PetscFunctionReturn(0);
853 }
854 
855 /* -------------------------------------------------------------------------------------------
856      The following set of functions are wrapper functions for AMS functions that
857 
858     1)  convert from string arguments to appropriate AMS arguments (int, double, char*, etc)
859     2)  call the AMS function
860     3)  convert from the AMS result arguments to string arguments
861 */
862 
863 #undef __FUNCT__
864 #define __FUNCT__ "YAML_AMS_Connect"
865 /*
866       Connects to the local AMS and gets only the first communication name
867 
868    Input Parameters:
869 .     none
870 
871    Output Parameter:
872 .     oarg1 - the string name of the first communicator
873 
874 */
875 PETSC_EXTERN PetscErrorCode YAML_AMS_Connect(PetscInt argc,char **args,PetscInt *argco,char ***argso)
876 {
877   PetscErrorCode ierr;
878   char           **list = 0;
879 
880   PetscFunctionBegin;
881   ierr = AMS_Connect(0,-1,&list);
882   if (ierr) {
883     ierr = PetscInfo1(NULL,"AMS_Connect() error %d\n",ierr);CHKERRQ(ierr);
884   } else if (!list) {
885     ierr = PetscInfo(NULL,"AMS_Connect() list empty, not running AMS server\n");CHKERRQ(ierr);
886   }
887   *argco = 1;
888   ierr   = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
889   if (list) {
890     ierr = PetscStrallocpy(list[0],&(*argso)[0]);CHKERRQ(ierr);
891   } else {
892     ierr = PetscStrallocpy("No AMS publisher running",&(*argso)[0]);CHKERRQ(ierr);
893   }
894   PetscFunctionReturn(0);
895 }
896 
897 #undef __FUNCT__
898 #define __FUNCT__ "YAML_AMS_Comm_attach"
899 /*
900       Attaches to an AMS communicator
901 
902    Input Parameter:
903 .     arg1 - string name of the communicator
904 
905    Output Parameter:
906 .     oarg1 - the integer name of the communicator
907 
908 */
909 PETSC_EXTERN PetscErrorCode YAML_AMS_Comm_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
910 {
911   PetscErrorCode ierr;
912   AMS_Comm       comm = -1;
913 
914   PetscFunctionBegin;
915   ierr = AMS_Comm_attach(args[0],&comm);
916   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Comm_attach() error %d\n",ierr);CHKERRQ(ierr);}
917   *argco = 1;
918   ierr   = PetscMalloc(sizeof(char*),argso);CHKERRQ(ierr);
919   ierr   = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
920   sprintf(argso[0][0],"%d",(int)comm);
921   PetscFunctionReturn(0);
922 }
923 
924 #undef __FUNCT__
925 #define __FUNCT__ "YAML_AMS_Comm_get_memory_list"
926 /*
927       Gets the list of memories on an AMS Comm
928 
929    Input Parameter:
930 .     arg1 - integer name of the communicator
931 
932    Output Parameter:
933 .     oarg1 - the list of names
934 
935 */
936 PETSC_EXTERN PetscErrorCode YAML_AMS_Comm_get_memory_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
937 {
938   PetscErrorCode ierr;
939   char           **mem_list;
940   AMS_Comm       comm;
941   PetscInt       i,iargco = 0;
942 
943   PetscFunctionBegin;
944   sscanf(args[0],"%d",&comm);
945   ierr = AMS_Comm_get_memory_list(comm,&mem_list);
946   if (ierr) {
947     ierr = PetscInfo1(NULL,"AMS_Comm_get_memory_list() error %d\n",ierr);CHKERRQ(ierr);
948   } else {
949     while (mem_list[iargco++]) ;
950     iargco--;
951 
952     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
953     for (i=0; i<iargco; i++) {
954       ierr = PetscStrallocpy(mem_list[i],(*argso)+i);CHKERRQ(ierr);
955     }
956   }
957   *argco = iargco;
958   PetscFunctionReturn(0);
959 }
960 
961 #undef __FUNCT__
962 #define __FUNCT__ "YAML_AMS_Memory_attach"
963 /*
964       Attaches to an AMS memory in a communicator
965 
966    Input Parameter:
967 .     arg1 - communicator
968 .     arg2 - string name of the memory
969 
970    Output Parameter:
971 .     oarg1 - the integer name of the memory
972 .     oarg2 - the integer step of the memory
973 
974 */
975 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_attach(PetscInt argc,char **args,PetscInt *argco,char ***argso)
976 {
977   PetscErrorCode ierr;
978   AMS_Comm       comm;
979   AMS_Memory     mem;
980   unsigned int   step;
981 
982   PetscFunctionBegin;
983   sscanf(args[0],"%d",&comm);
984   ierr = AMS_Memory_attach(comm,args[1],&mem,&step);
985   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Memory_attach() error %d\n",ierr);CHKERRQ(ierr);}
986   *argco = 2;
987   ierr   = PetscMalloc(2*sizeof(char*),argso);CHKERRQ(ierr);
988   ierr   = PetscMalloc(3*sizeof(char*),&argso[0][0]);CHKERRQ(ierr);
989   sprintf(argso[0][0],"%d",(int)mem);
990   ierr = PetscMalloc(3*sizeof(char*),&argso[0][1]);CHKERRQ(ierr);
991   sprintf(argso[0][1],"%d",(int)step);
992   PetscFunctionReturn(0);
993 }
994 
995 #undef __FUNCT__
996 #define __FUNCT__ "YAML_AMS_Memory_get_field_list"
997 /*
998       Gets the list of fields on an AMS Memory
999 
1000    Input Parameter:
1001 .     arg1 - integer name of the memory
1002 
1003    Output Parameter:
1004 .     oarg1 - the list of names
1005 
1006 */
1007 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_get_field_list(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1008 {
1009   PetscErrorCode ierr;
1010   char           **field_list;
1011   AMS_Memory     mem;
1012   PetscInt       i,iargco = 0;
1013 
1014   PetscFunctionBegin;
1015   sscanf(args[0],"%d",&mem);
1016   ierr = AMS_Memory_get_field_list(mem,&field_list);
1017   if (ierr) {
1018     ierr = PetscInfo1(NULL,"AMS_Memory_get_field_list() error %d\n",ierr);CHKERRQ(ierr);
1019   } else {
1020     while (field_list[iargco++]) ;
1021     iargco--;
1022 
1023     ierr = PetscMalloc((iargco)*sizeof(char*),argso);CHKERRQ(ierr);
1024     for (i=0; i<iargco; i++) {
1025       ierr = PetscStrallocpy(field_list[i],(*argso)+i);CHKERRQ(ierr);
1026     }
1027   }
1028   *argco = iargco;
1029   PetscFunctionReturn(0);
1030 }
1031 
1032 const char *AMS_Data_types[] = {"AMS_DATA_UNDEF","AMS_BOOLEAN","AMS_INT","AMS_FLOAT","AMS_DOUBLE","AMS_STRING","AMS_Data_type","AMS_",0};
1033 const char *AMS_Memory_types[] = {"AMS_MEMORY_UNDEF","AMS_READ","AMS_WRITE","AMS_Memory_type","AMS_",0};
1034 const char *AMS_Shared_types[] = {"AMS_SHARED_UNDEF","AMS_COMMON","AMS_REDUCED","AMS_DISTRIBUTED","AMS_Shared_type","AMS_",0};
1035 const char *AMS_Reduction_types[] = {"AMS_REDUCTION_WHY_NOT_UNDEF?","AMS_SUM","AMS_MAX","AMS_MIN","AMS_REDUCTION_UNDEF","AMS_Reduction_type","AMS_",0};
1036 
1037 #undef __FUNCT__
1038 #define __FUNCT__ "YAML_AMS_Memory_get_field_info"
1039 /*
1040       Gets information about a field
1041 
1042    Input Parameter:
1043 .     arg1 - memory
1044 .     arg2 - string name of the field
1045 
1046    Output Parameter:
1047 
1048 */
1049 PETSC_EXTERN PetscErrorCode YAML_AMS_Memory_get_field_info(PetscInt argc,char **args,PetscInt *argco,char ***argso)
1050 {
1051   PetscErrorCode     ierr;
1052   AMS_Memory         mem;
1053   void               *addr;
1054   int                len;
1055   AMS_Data_type      dtype;
1056   AMS_Memory_type    mtype;
1057   AMS_Shared_type    stype;
1058   AMS_Reduction_type rtype;
1059   PetscInt           i;
1060 
1061   PetscFunctionBegin;
1062   sscanf(args[0],"%d",&mem);
1063   ierr = AMS_Memory_get_field_info(mem,args[1],&addr,&len,&dtype,&mtype,&stype,&rtype);
1064   if (ierr) {ierr = PetscInfo1(NULL,"AMS_Memory_get_field_info() error %d\n",ierr);CHKERRQ(ierr);}
1065   *argco = 4 + len;
1066   ierr   = PetscMalloc((*argco)*sizeof(char*),argso);CHKERRQ(ierr);
1067   ierr   = PetscStrallocpy(AMS_Data_types[dtype],&argso[0][0]);CHKERRQ(ierr);
1068   ierr   = PetscStrallocpy(AMS_Memory_types[mtype],&argso[0][1]);CHKERRQ(ierr);
1069   ierr   = PetscStrallocpy(AMS_Shared_types[stype],&argso[0][2]);CHKERRQ(ierr);
1070   ierr   = PetscStrallocpy(AMS_Reduction_types[rtype],&argso[0][3]);CHKERRQ(ierr);
1071   for (i=0; i<len; i++) {
1072     if (dtype == AMS_STRING) {
1073       ierr = PetscStrallocpy(*(const char**)addr,&argso[0][4+i]);CHKERRQ(ierr);
1074     } else if (dtype == AMS_DOUBLE) {
1075       ierr = PetscMalloc(20*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
1076       sprintf(argso[0][4+i],"%18.16e",*(double*)addr);
1077     } else if (dtype == AMS_INT) {
1078       ierr = PetscMalloc(10*sizeof(char),&argso[0][4+i]);CHKERRQ(ierr);
1079       sprintf(argso[0][4+i],"%d",*(int*)addr);
1080     } else if (dtype == AMS_BOOLEAN) {
1081       if (*(int*)addr) {
1082         ierr = PetscStrallocpy("true",&argso[0][4+i]);CHKERRQ(ierr);
1083       } else {
1084         ierr = PetscStrallocpy("false",&argso[0][4+i]);CHKERRQ(ierr);
1085       }
1086     } else {
1087       ierr = PetscStrallocpy("Not yet done",&argso[0][4+i]);CHKERRQ(ierr);
1088     }
1089   }
1090   PetscFunctionReturn(0);
1091 }
1092 
1093 #include "yaml.h"
1094 #undef __FUNCT__
1095 #define __FUNCT__ "PetscProcessYAMLRPC"
1096 /*
1097      1) Parses a YAML/JSON-RPC function call generating a function name for an AMS wrapper function and the arguments to the function
1098      2) loads the function with dlsym(),
1099      3) calls the wrapper function with the arguments
1100      4) converts the result arguments back to YAML/JSON.
1101 */
1102 static PetscErrorCode PetscProcessYAMLRPC(const char *request,char **result)
1103 {
1104   yaml_parser_t  parser;
1105   yaml_event_t   event;
1106   int            done  = 0;
1107   int            count = 0;
1108   size_t         len;
1109   PetscErrorCode ierr;
1110   PetscBool      method,params,id;
1111   char           *methodname,*idname,**args,**argso = 0;
1112   PetscInt       argc = 0,argco,i;
1113   PetscErrorCode (*fun)(PetscInt,char**,PetscInt*,char***);
1114 
1115   PetscFunctionBegin;
1116   ierr = PetscMalloc(sizeof(char*),&args);CHKERRQ(ierr);
1117   yaml_parser_initialize(&parser);
1118   PetscStrlen(request,&len);
1119   yaml_parser_set_input_string(&parser, (unsigned char*)request, len);
1120 
1121   /* this is totally bogus; it only handles the simple JSON-RPC messages */
1122   while (!done) {
1123     if (!yaml_parser_parse(&parser, &event)) {
1124       ierr = PetscInfo(NULL,"Found error in yaml/json\n");CHKERRQ(ierr);
1125       break;
1126     }
1127     done = (event.type == YAML_STREAM_END_EVENT);
1128     switch (event.type) {
1129     case YAML_STREAM_START_EVENT:
1130       ierr = PetscInfo(NULL,"Stream start\n");CHKERRQ(ierr);
1131       break;
1132     case YAML_STREAM_END_EVENT:
1133       ierr = PetscInfo(NULL,"Stream end\n");CHKERRQ(ierr);
1134       break;
1135     case YAML_DOCUMENT_START_EVENT:
1136       ierr = PetscInfo(NULL,"Document start\n");CHKERRQ(ierr);
1137       break;
1138     case YAML_DOCUMENT_END_EVENT:
1139       ierr = PetscInfo(NULL,"Document end\n");CHKERRQ(ierr);
1140       break;
1141     case YAML_MAPPING_START_EVENT:
1142       ierr = PetscInfo(NULL,"Mapping start event\n");CHKERRQ(ierr);
1143       break;
1144     case YAML_MAPPING_END_EVENT:
1145       ierr = PetscInfo(NULL,"Mapping end event \n");CHKERRQ(ierr);
1146       break;
1147     case YAML_ALIAS_EVENT:
1148       ierr = PetscInfo1(NULL,"Alias event %s\n",event.data.alias.anchor);CHKERRQ(ierr);
1149       break;
1150     case YAML_SCALAR_EVENT:
1151       ierr = PetscInfo1(NULL,"Scalar event %s\n",event.data.scalar.value);CHKERRQ(ierr);
1152       ierr = PetscStrcmp((char*)event.data.scalar.value,"method",&method);CHKERRQ(ierr);
1153       ierr = PetscStrcmp((char*)event.data.scalar.value,"params",&params);CHKERRQ(ierr);
1154       ierr = PetscStrcmp((char*)event.data.scalar.value,"id",&id);CHKERRQ(ierr);
1155       if (method) {
1156         yaml_event_delete(&event);
1157         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1158         ierr = PetscInfo1(NULL,"Method %s\n",event.data.scalar.value);CHKERRQ(ierr);
1159         ierr = PetscStrallocpy((char*)event.data.scalar.value,&methodname);CHKERRQ(ierr);
1160       } else if (id) {
1161         yaml_event_delete(&event);
1162         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1163         ierr = PetscInfo1(NULL,"Id %s\n",event.data.scalar.value);CHKERRQ(ierr);
1164         ierr = PetscStrallocpy((char*)event.data.scalar.value,&idname);CHKERRQ(ierr);
1165       } else if (params) {
1166         yaml_event_delete(&event);
1167         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1168         yaml_event_delete(&event);
1169         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1170         while (event.type != YAML_SEQUENCE_END_EVENT) {
1171           ierr = PetscInfo1(NULL,"  Parameter %s\n",event.data.scalar.value);CHKERRQ(ierr);
1172           ierr = PetscStrallocpy((char*)event.data.scalar.value,&args[argc++]);CHKERRQ(ierr);
1173           yaml_event_delete(&event);
1174           ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1175         }
1176       } else { /* ignore all the other variables in the mapping */
1177         yaml_event_delete(&event);
1178         ierr = yaml_parser_parse(&parser, &event);CHKERRQ(!ierr);
1179       }
1180       break;
1181     case YAML_SEQUENCE_START_EVENT:
1182       ierr = PetscInfo(NULL,"Sequence start event \n");CHKERRQ(ierr);
1183       break;
1184     case YAML_SEQUENCE_END_EVENT:
1185       ierr = PetscInfo(NULL,"Sequence end event \n");CHKERRQ(ierr);
1186       break;
1187     default:
1188       /* It couldn't really happen. */
1189       break;
1190     }
1191 
1192     yaml_event_delete(&event);
1193     count++;
1194   }
1195   yaml_parser_delete(&parser);
1196 
1197   ierr = PetscDLLibrarySym(PETSC_COMM_SELF,NULL,NULL,methodname,(void**)&fun);CHKERRQ(ierr);
1198   if (fun) {
1199     ierr = PetscInfo1(NULL,"Located function %s and running it\n",methodname);CHKERRQ(ierr);
1200     ierr = (*fun)(argc,args,&argco,&argso);CHKERRQ(ierr);
1201   } else {
1202     ierr = PetscInfo1(NULL,"Did not locate function %s skipping it\n",methodname);CHKERRQ(ierr);
1203   }
1204 
1205   for (i=0; i<argc; i++) {
1206     ierr = PetscFree(args[i]);CHKERRQ(ierr);
1207   }
1208   ierr = PetscFree(args);CHKERRQ(ierr);
1209   ierr = PetscFree(methodname);CHKERRQ(ierr);
1210 
1211   /* convert the result back to YAML/JSON; should use YAML/JSON encoder, does not handle zero return arguments */
1212   ierr = PetscMalloc(1024,result);CHKERRQ(ierr);
1213   ierr = PetscStrcpy(*result,"{\"error\": null, \"id\": \"");CHKERRQ(ierr);
1214   ierr = PetscStrcat(*result,idname);CHKERRQ(ierr);
1215   ierr = PetscStrcat(*result,"\", \"result\" : ");CHKERRQ(ierr);
1216   if (argco > 1) {ierr = PetscStrcat(*result,"[");CHKERRQ(ierr);}
1217   for (i=0; i<argco; i++) {
1218     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1219     ierr = PetscStrcat(*result,argso[i]);CHKERRQ(ierr);
1220     ierr = PetscStrcat(*result,"\"");CHKERRQ(ierr);
1221     if (i < argco-1) {ierr = PetscStrcat(*result,",");CHKERRQ(ierr);}
1222   }
1223   if (argco > 1) {ierr = PetscStrcat(*result,"]");CHKERRQ(ierr);}
1224   ierr = PetscStrcat(*result,"}");CHKERRQ(ierr);
1225   ierr = PetscInfo1(NULL,"YAML/JSON result of function %s\n",*result);CHKERRQ(ierr);
1226 
1227   /* free work space */
1228   ierr = PetscFree(idname);CHKERRQ(ierr);
1229   for (i=0; i<argco; i++) {
1230     ierr = PetscFree(argso[i]);CHKERRQ(ierr);
1231   }
1232   ierr = PetscFree(argso);CHKERRQ(ierr);
1233   PetscFunctionReturn(0);
1234 }
1235 
1236 #undef __FUNCT__
1237 #define __FUNCT__ "PetscWebServeRequestPostAMSJSONRPC"
1238 /*@C
1239       PetscWebServeRequestPostAMSJSONRPC - serves a single web POST request based on JSON-RPC
1240 
1241        This function allows a Javascript program (running in the browser) to make an AMS function
1242        call via JSON-RPC
1243 
1244        The currently available Javascript programs are in ${PETSC_DIR}/include/web
1245 
1246     Not collective
1247 
1248   Input Parameters:
1249 .   fd - the network file to read and write from
1250 -   path - the command from the server
1251 
1252     Level: developer
1253 
1254 .seealso: PetscWebServe()
1255 @*/
1256 static PetscErrorCode  PetscWebServeRequestPostAMSJSONRPC(FILE *fd,const char path[])
1257 {
1258   PetscErrorCode ierr;
1259   char           buf[16000];
1260   char           *result;
1261   int            len = -1;
1262   size_t         elen;
1263   char           *fnd;
1264 
1265   PetscFunctionBegin;
1266   while (PETSC_TRUE) {
1267 
1268     if (!fgets(buf, sizeof(buf), fd)) {
1269       ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1270       PetscFunctionReturn(0);
1271     }
1272     ierr = PetscInfo1(NULL,"POSTED header: %s",buf);CHKERRQ(ierr);
1273     ierr = PetscStrstr(buf,"Content-Type:",&fnd);CHKERRQ(ierr);
1274     if (fnd) {
1275       ierr = PetscStrstr(buf,"application/json-rpc",&fnd);CHKERRQ(ierr);
1276       if (!fnd) {
1277         ierr = PetscInfo(NULL,"POST content is not json-rpc, skipping post\n");CHKERRQ(ierr);
1278         PetscFunctionReturn(0);
1279       }
1280     }
1281     ierr = PetscStrstr(buf,"Content-Length:",&fnd);CHKERRQ(ierr);
1282     if (fnd) {
1283       sscanf(buf,"Content-Length: %d\n",&len);
1284       ierr = PetscInfo1(NULL,"POSTED Content-Length: %d\n",len);CHKERRQ(ierr);
1285     }
1286     if (buf[0] == '\r') break;
1287   }
1288   if (len == -1) {
1289     ierr = PetscInfo(NULL,"Did not find Content-Length, giving up\n");CHKERRQ(ierr);
1290   }
1291 
1292   if (!fgets(buf, len+1, fd)) { /* why is this len + 1? */
1293     ierr = PetscInfo(NULL,"Cannot read POST data, giving up\n");CHKERRQ(ierr);
1294     PetscFunctionReturn(0);
1295   }
1296   ierr = PetscInfo1(NULL,"POSTED JSON/RPC request: %s\n",buf);CHKERRQ(ierr);
1297   printf("%s",buf);
1298   fseek(fd, 0, SEEK_CUR); /* Force change of stream direction */
1299   ierr = PetscProcessYAMLRPC(buf,&result);CHKERRQ(ierr);
1300   ierr = PetscStrlen(result,&elen);CHKERRQ(ierr);
1301   ierr = PetscWebSendHeader(fd, 200, "OK", NULL, "application/json-rpc",(int)elen);CHKERRQ(ierr);
1302   fprintf(fd, "%s",result);
1303   ierr = PetscInfo(NULL,"Completed AMS JSON-RPC function call\n");CHKERRQ(ierr);
1304   PetscFunctionReturn(0);
1305 }
1306 #endif
1307 
1308 #undef __FUNCT__
1309 #define __FUNCT__ "PetscWebServeRequest"
1310 /*@C
1311       PetscWebServeRequest - serves a single web request
1312 
1313     Not collective
1314 
1315   Input Parameters:
1316 .   port - the port
1317 
1318     Level: developer
1319 
1320 .seealso: PetscWebServe()
1321 @*/
1322 static PetscErrorCode  PetscWebServeRequest(int port)
1323 {
1324   PetscErrorCode ierr;
1325   FILE           *fd;
1326   char           buf[4096];
1327   char           *method, *path, *protocol;
1328   PetscBool      flg;
1329   PetscToken     tok;
1330 
1331   PetscFunctionBegin;
1332   fd = fdopen(port, "r+");
1333 
1334   ierr = PetscInfo(NULL,"Processing web request\n");CHKERRQ(ierr);
1335   if (!fgets(buf, sizeof(buf), fd)) {
1336     ierr = PetscInfo(NULL,"Cannot read web request, giving up\n");CHKERRQ(ierr);
1337     goto theend;
1338   }
1339   ierr = PetscInfo1(NULL,"Processing web request %s",buf);CHKERRQ(ierr);
1340 
1341   ierr = PetscTokenCreate(buf,' ',&tok);CHKERRQ(ierr);
1342   ierr = PetscTokenFind(tok,&method);CHKERRQ(ierr);
1343   ierr = PetscTokenFind(tok,&path);CHKERRQ(ierr);
1344   ierr = PetscTokenFind(tok,&protocol);CHKERRQ(ierr);
1345 
1346   if (!method || !path || !protocol) {
1347     ierr = PetscInfo(NULL,"Web request not well formatted, giving up\n");CHKERRQ(ierr);
1348     goto theend;
1349   }
1350 
1351   ierr = PetscStrcmp(method,"GET",&flg);
1352   if (flg) {
1353       ierr = PetscWebServeRequestGet(fd,path);CHKERRQ(ierr);
1354   } else {
1355 #if defined(PETSC_HAVE_YAML)
1356     ierr = PetscStrcmp(method,"POST",&flg);
1357     if (flg) {
1358       ierr = PetscWebServeRequestPostAMSJSONRPC(fd,path);CHKERRQ(ierr);
1359     } else {
1360 #else
1361     {
1362 #endif
1363       ierr = PetscWebSendError(fd, 501, "Not supported", NULL, "Method is not supported.");CHKERRQ(ierr);
1364       ierr = PetscInfo(NULL,"Web request not a GET or POST, giving up\n");CHKERRQ(ierr);
1365     }
1366   }
1367 theend:
1368   ierr = PetscTokenDestroy(&tok);CHKERRQ(ierr);
1369   fclose(fd);
1370   ierr = PetscInfo1(NULL,"Finished processing request %s\n",method);CHKERRQ(ierr);
1371   PetscFunctionReturn(0);
1372 }
1373 
1374 #undef __FUNCT__
1375 #define __FUNCT__ "PetscWebServeWait"
1376 /*@C
1377       PetscWebServeWait - waits for requests on a thread
1378 
1379     Not collective
1380 
1381   Input Parameter:
1382 .   port - port to listen on
1383 
1384     Level: developer
1385 
1386 .seealso: PetscViewerSocketOpen(), PetscWebServe()
1387 @*/
1388 void *PetscWebServeWait(int *port)
1389 {
1390   PetscErrorCode ierr;
1391   int            iport,listenport,tport = *port;
1392 
1393   ierr = PetscInfo1(NULL,"Starting webserver at port %d\n",tport);if (ierr) return 0;
1394   ierr = PetscFree(port);if (ierr) return 0;
1395   ierr = PetscSocketEstablish(tport,&listenport);if (ierr) return 0;
1396   while (1) {
1397     ierr = PetscSocketListen(listenport,&iport);if (ierr) return 0;
1398     ierr = PetscWebServeRequest(iport);if (ierr) return 0;
1399     close(iport);
1400   }
1401   close(listenport);
1402   return 0;
1403 }
1404 
1405 #undef __FUNCT__
1406 #define __FUNCT__ "PetscWebServe"
1407 /*@
1408       PetscWebServe - start up the PETSc web server and respond to requests
1409 
1410     Not collective - only does something on process zero of the communicator
1411 
1412   Input Parameters:
1413 +   comm - the MPI communicator
1414 -   port - port to listen on
1415 
1416   Options Database Key:
1417 +  -server <port> - start PETSc webserver (default port is 8080)
1418 -  -ams_publish_objects
1419 
1420 
1421    Notes: Point your browser to http://hostname:8080   to access the PETSc web server, where hostname is the name of your machine.
1422       If you are running PETSc on your local machine you can use http://localhost:8080
1423 
1424       If the PETSc program completes before you connect with the browser you will not be able to connect to the PETSc webserver.
1425 
1426       Read the top of $PETSC_DIR/include/web/AMSJavascript.py before running.
1427 
1428     Level: intermediate
1429 
1430 .seealso: PetscViewerSocketOpen()
1431 @*/
1432 PetscErrorCode  PetscWebServe(MPI_Comm comm,int port)
1433 {
1434   PetscErrorCode ierr;
1435   PetscMPIInt    rank;
1436   pthread_t      thread;
1437   int            *trueport;
1438 
1439   PetscFunctionBegin;
1440   if (port < 1 && port != PETSC_DEFAULT && port != PETSC_DECIDE) SETERRQ1(PETSC_COMM_WORLD,PETSC_ERR_ARG_WRONG,"Cannot use negative port number %d",port);
1441   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1442   if (rank) PetscFunctionReturn(0);
1443 
1444   if (port == PETSC_DECIDE || port == PETSC_DEFAULT) port = 8080;
1445   ierr = PetscMalloc(1*sizeof(int),&trueport);CHKERRQ(ierr); /* malloc this so it still exists in thread */
1446   *trueport = port;
1447   ierr = pthread_create(&thread, NULL, (void *(*)(void*))PetscWebServeWait, trueport);CHKERRQ(ierr);
1448   PetscFunctionReturn(0);
1449 }
1450 #endif
1451 
1452 
1453 
1454 
1455 
1456 
1457 
1458 
1459 
1460 
1461 
1462 
1463 
1464 
1465