source: trunk/src/seismic_processing/gmew/gm_config.c @ 7593

Revision 7593, 41.7 KB checked in by paulf, 11 months ago (diff)

added ChannelNumberMap? to gmew to map numbers to components....before this 2 and 3 were default mapped to N and E respectively

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 *   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
3 *   CHECKED IT OUT USING THE COMMAND CHECKOUT.
4 *
5 *    $Id$
6 *
7 *    Revision history:
8 *     $Log$
9 *     Revision 1.11  2009/08/25 00:10:40  paulf
10 *     added extraDelay parameter go gmew
11 *
12 *     Revision 1.10  2007/05/15 17:32:42  paulf
13 *     fixed qsort call (thanks to Ali M. from Utah for the catch
14 *
15 *     Revision 1.9  2006/03/15 14:21:54  paulf
16 *     SCNL version of gmew v0.2.0
17 *
18 *     Revision 1.8  2002/09/25 17:34:56  dhanych
19 *     added default value (3.0) for parameter snrThresh to initGM()
20 *
21 *     Revision 1.7  2002/02/28 17:03:36  lucky
22 *     Moved gma.c and gma.h to libsrc and main include
23 *
24 *     Revision 1.6  2001/07/18 19:41:36  lombard
25 *     Changed XMLDir, TempDir and MappingFile in GMPARAMS struct from string
26 *     arrays to string pointers. Changed gm_config.c and gm_util.c to support thes
27 *     changes. This solved a problem where the GMPARAMS structure was getting
28 *     corrupted when a pointer to it was passed into getGMFromTrace().
29 *     It's not clear why this was necessary; purify didn't complain.
30 *
31 *     Revision 1.5  2001/07/18 19:18:25  lucky
32 *     *** empty log message ***
33 *
34 *     Revision 1.4  2001/06/11 01:27:27  lombard
35 *     cleanup
36 *
37 *     Revision 1.3  2001/06/10 21:27:36  lombard
38 *     Changed single transport ring to input and output rings.
39 *     Added ability to handle multiple getEventsFrom commands.
40 *     Fixed handling of waveservers in config file.
41 *
42 *     Revision 1.2  2001/04/11 21:12:20  lombard
43 *     ../localmag/site.h ../localmag/lm_site.h
44 *
45 *     Revision 1.1  2001/03/30 19:14:25  lombard
46 *     Initial revision
47 *
48 *
49 *
50 */
51/*
52 * gm_config.c: routines to configure the gm module.
53 */
54
55
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59
60#include "earthworm.h"
61#include "kom.h"
62#include "tlay.h"
63#include "ws_clientII.h"
64#include "gma.h"
65#include "gm_sac.h"
66#include "gm_util.h"
67#include "gm_ws.h"
68#include "gm_xml.h"
69#include "../localmag/lm_site.h"
70
71/* Internal Function Prototypes */
72static void initGM(GMPARAMS *);
73static int ReadConfig (GMPARAMS *, char * );
74
75#ifdef _WINNT
76/* Handle deprecation of strdup in windows */
77static char* mystrdup( const char* src ) {
78        char* dest = malloc( strlen(src) + 1 );
79        if ( dest != NULL )
80                strcpy( dest, src );
81        return dest;
82}
83#else
84#define mystrdup strdup
85#endif
86
87/*
88 * Configure: do all the configuration of gmew.
89 * This includes initializing the GMPARAMS structure, parsing the command-line
90 * arguments, parsing the config file, and checking configuration settings
91 * for consistency.
92 *    Returns: 0 on success
93 *            -1 on failure
94 */
95int Configure( GMPARAMS *pgmParams, int argc, char **argv, EVENT *pEvt, char *vsn)
96{
97  int rc = 0, logSwitch = 1;
98  int lenT, lenX;
99  char *configFile;
100  char *str, servDir[GM_MAXTXT];
101 
102  /* Set initial values, then parse the command-line options */
103  initGM( pgmParams );
104  if (argc == 2)
105    configFile = argv[1];
106  else
107  {
108    fprintf(stderr, "Usage: %s config-file\n", argv[0]);
109    fprintf(stderr, "   Version %s\n", vsn );
110    exit( -1 );
111  }
112   
113  /* Initialize the Earthworm logit system */
114  logit_init(configFile, 0, MAX_BYTES_PER_EQ, logSwitch);
115
116  /* Read the configuration file */
117  if ( (rc = ReadConfig( pgmParams, configFile )) < 0)
118    return rc;   /* Error; ReadConfig already complained */
119
120  /* Set defaults if they weren't already set */
121  if (pgmParams->traceSource == GM_UNDEF )
122    pgmParams->traceSource = GM_TS_WS;
123  if (pgmParams->saveTrace == GM_UNDEF)
124    pgmParams->saveTrace = GM_ST_NO;
125
126  /* Initialize the trace arrays.                                        */
127  if ( (rc = initBufs( pgmParams->maxTrace )) < 0)
128  {     /* initBufs already complained, so be silent here */
129    return rc;
130  }
131
132  switch( pgmParams->traceSource)
133  {
134  case GM_TS_WS:
135    if (pgmParams->pWSV == (WS_ACCESS *)NULL)
136    {   /* Set the default traceSource to wave_servers listed in *
137         * ${EW_PARAMS}/servers                                  */
138      if ( (str = getenv("EW_PARAMS")) == NULL)
139      {
140        logit("e", "Configure: environment variable EW_PARAMS not defined\n");
141        return -1;
142      }
143      if (strlen(str) > GM_MAXTXT - (strlen(DEF_SERVER) + 2))
144      {
145        logit("e", "Configure: environment variable EW_PARAMS too long;"
146              " increase GM_MAXTXT and recompile\n");
147        return -1;
148      }
149      sprintf(servDir, "%s/%s", str, DEF_SERVER);
150      if ( (pgmParams->pWSV = 
151            (WS_ACCESS *)calloc(1, sizeof(WS_ACCESS))) == 
152           (WS_ACCESS *)NULL)
153      {
154        logit("e", "Configure: out of memory for WS_ACCESS\n");
155        return -1;
156      }
157      if ( (pgmParams->pWSV->serverFile = mystrdup(servDir)) == NULL)
158      {
159        logit("e", "Configure: out of memory for serverFile\n");
160        return -1;
161      }
162    }
163    if (pgmParams->pWSV->pList == (SERVER *)NULL)
164    {
165      if (readServerFile(pgmParams) < 0)
166        return -1;
167    }
168    if (initWsBuf(pgmParams->maxTrace) < 0)
169    {
170      logit("e", "Configure: out of memory for trace_buf buffer\n");
171      return -1;
172    }
173    if (pgmParams->wsTimeout == 0)
174      pgmParams->wsTimeout = 5000;  /* Default, 5 seconds */
175    break;
176#ifdef EWDB
177  case GM_TS_EWDB:
178    if (pgmParams->pDBaccess == (DBACCESS *)NULL)
179    {
180      logit("e", 
181            "Configure: traceSource is EWDB but EWDBaccess not given\n");
182      rc = -1;
183    }
184    break;
185#endif
186  default:
187    logit("e", "Configure: unknown trace source <%d>.\n", 
188          pgmParams->traceSource);
189    rc = -1;
190  }
191
192  switch( pgmParams->respSource )
193  {
194  case GM_UNDEF:
195    logit("e", "Configure: required response source not specified\n");
196    rc = -1;
197    break;
198  case GM_RS_FILE:
199    /* Nothing to do for this */
200    break;
201#ifdef EWDB
202  case GM_RS_EWDB:
203    if (pgmParams->pDBaccess == NULL)
204    {
205      logit("e", 
206            "Configure: response source is EWDB but EWDBaccess not given\n");
207      rc = -1;
208    }
209    break;
210#endif
211  default:
212    logit("e", "Configure: unknown response source %d\n", 
213          pgmParams->respSource);
214    rc = -1;
215  }
216
217  /* Station Location Source: readConfig requires that it be set,
218        unless we're only responding to alarm messages */
219  switch (pgmParams->staLoc)
220  {
221  case GM_UNDEF:
222    break;
223  case GM_SL_HYP:
224    if ( site_read(pgmParams->staLocFile) < 0)
225      rc = -1;
226    break;
227#ifdef EWDB
228  case GM_SL_EWDB:
229    if ( pgmParams->pDBaccess == (DBACCESS *)NULL)
230    {
231      logit("e", "Configure: staLoc is EWDB but EWDBaccess not given\n");
232      rc = -1;
233    }
234    break;
235#endif
236  default:
237    logit("e", "Configure: unknown staLoc <%d>\n", pgmParams->staLoc);
238    rc = -1;
239  }
240 
241  if (pgmParams->saveTrace == GM_ST_SAC)
242  {  /* Initialize the SAC data array */
243    if ( initSACBuf( pgmParams->maxTrace ) < 0)
244    {
245      logit("e", "Configure: out of memory for SAC data\n");
246      return -1;
247    }
248  }
249
250  lenT = lenX = 0;
251  if (pgmParams->TempDir)
252    lenT = strlen(pgmParams->TempDir);
253  if (pgmParams->XMLDir)
254    lenX = strlen(pgmParams->XMLDir);
255  if ( lenT == 0 && lenX != 0)
256  {
257    logit("e", "XMLDir given but TempDir is missing\n");
258    rc = -1;
259  }
260
261  if (rc == 0)
262  {    /* Initialize the station list */
263    if ( (pEvt->Sta = (STA *)calloc( pgmParams->maxSta, sizeof(STA))) == 
264         (STA *)NULL)
265    {
266      logit("et", "Configure: out of memory for STA array\n");
267      return -1;
268    }
269
270    /* Turn on some debugging options */
271    if (pgmParams->debug & GM_DBG_WSC)
272      (void)setWsClient_ewDebug(1);
273 
274    if (pgmParams->debug & (GM_DBG_PZG | GM_DBG_TRS | GM_DBG_ARS))
275      transferDebug(pgmParams->debug >> 5);
276
277    /* Sort the SCNLPAR array to make searching more efficient */
278    if (pgmParams->numSCNLPar > 0)
279      qsort(pgmParams->pSCNLPar, pgmParams->numSCNLPar, sizeof(SCNLPAR),
280            CompareSCNLPARs);
281   
282    /* Initialize the XML mapping file */
283    if (lenX > 0)
284    {
285      if (pgmParams->MappingFile && strlen(pgmParams->MappingFile) != 0)
286      {
287        if (initMappings( pgmParams->MappingFile ) < 0)
288        {
289          logit("et", "gmew: error initializing mappings; exitting!\n");
290          rc = -1;
291        }
292      }
293    }
294  }
295 
296  return rc;
297}
298
299
300
301#define NUMREQ 9       /* Number of parameters that MUST be    */
302/*   set from the config file.          */
303
304/*      Function: ReadConfig                                            */
305static int ReadConfig (GMPARAMS *pgmParams, char *configfile )
306{
307  char     init[NUMREQ];  /* init flags, one byte for each required command */
308  int      nmiss;         /* number of required commands that were missed   */
309  char     *com;
310  char     *str;
311  char     *processor;
312  int      nfiles, rc;
313  int      i;
314  int      err = 0;
315  double dummy;
316  SCNLSEL   *newSel, *pAdd, *pDel;
317  char configPath[GM_MAXTXT], *paramsDir;
318  GMEW *pEW;
319 
320 
321  pEW = pgmParams->pEW;
322
323  pgmParams->waitTime=0;        /* don't wait by default since this seems to work for many small networks */
324 
325  pgmParams->LookAtVersion = vAll;   /* Look at all versions of all events */
326
327  pgmParams->alarmDuration=0; /* default: ignore alarm messages */
328  pgmParams->allowDuplicates=0; /* default: ignore dup channel names (including location code diffs) */
329  pgmParams->sendActivate=0; /* default: do not send ACTIVATE messages when done with XML files */
330 
331  /* Set to zero one init flag for each required command */
332  for (i = 0; i < NUMREQ; i++)
333    init[i] = 0;
334
335  /* Open the main configuration file
336**********************************/
337  nfiles = k_open (configfile); 
338  if (nfiles == 0) 
339  {
340    if ( (paramsDir = getenv("EW_PARAMS")) == NULL)
341    {
342      fprintf(stderr, "gma: Error opening command file <%s>; EW_PARAMS not set\n", 
343              configfile);
344      return -1;
345    }
346    strcpy(configPath, paramsDir);
347    if (configPath[strlen(configPath)-1] != '/' || 
348        configPath[strlen(configPath)-1] != '\\')
349      strcat(configPath, "/");
350    strcat(configPath, configfile);
351    nfiles = k_open (configPath); 
352    if (nfiles == 0) 
353    {
354      fprintf(stderr, "gma: Error opening command file <%s> or <%s>\n", 
355              configfile, configPath);
356      return -1;
357    }
358  }
359
360  /* Process all command files
361***************************/
362  while (nfiles > 0)   /* While there are command files open */
363  {
364    while (k_rd ())        /* Read next line from active file  */
365    { 
366      com = k_str ();         /* Get the first token from line */
367
368      processor = "ReadConfig";
369     
370      /* Ignore blank lines & comments
371*******************************/
372      if (!com)
373        continue;
374      if (com[0] == '#')
375        continue;
376
377     
378     
379      /* Open a nested configuration file */
380      if (com[0] == '@') 
381      {
382        if ( (rc = k_open (&com[1])) == 0)
383        {
384          fprintf(stderr, "gma: Error opening command file <%s>\n", 
385                  &com[1]);
386          return -1;
387        }
388        nfiles = rc;
389        continue;
390      }
391
392      /* Station location source: required to process HYP2000ARC messages */
393      else if (k_its("staLoc") )
394      {
395        if ( (str = k_str()) )
396        {
397          if (k_its("File") )
398          {
399            if ( (str = k_str()) )
400            {
401              if ( (pgmParams->staLocFile = mystrdup(str)) == NULL)
402              {
403                logit("e", "ReadConfig: out of memory for staLoc\n");
404                return -1;
405              }
406              pgmParams->staLoc = GM_SL_HYP;
407              init[0] = 1;
408            }
409            else
410            {
411              logit("e", "ReadConfig: \"staLoc File\" missing filename\n");
412              err = -1;
413            }
414          }
415#ifdef EWDB
416          else if (k_its("EWDB") )
417          {
418            pgmParams->staLoc = GM_SL_EWDB;
419            init[0] = 1;
420          }
421#endif
422          else
423          {
424            logit("e", "ReadConfig: Unknown \"staLoc\": <%s>\n", str);
425            err = -1;
426          }
427        }
428        else
429        {
430          logit("e", "ReadConfig: \"staLoc\" missing argument\n");
431          err = -1;
432        }
433      }
434     
435      /* MaxSta: required */
436      else if (k_its("maxSta") )
437      {
438        pgmParams->maxSta = k_int();
439        /* tell lm_site.c about max size */
440        set_maxsite( pgmParams->maxSta );
441        init[1] = 1;
442      }
443     
444      /* MaxDist: required to process HYP2000ARC messages */
445      else if (k_its("maxDist") )
446      {
447        pgmParams->maxDist = k_val();
448        init[2] = 1;
449      }
450     
451      /* maxTrace: required */
452      else if (k_its("maxTrace") )
453      {
454        pgmParams->maxTrace = (long)k_int();
455        init[3] = 1;
456      }
457
458      else if (k_its("ChannelNumberMap") )
459      {
460        if ( (str = k_str()) )
461        {
462          if (strlen(str) > 3) 
463          {
464            logit("e", "ReadConfig: ChannelNumberMap is too long, only 3 chars allowed\n");
465            err = -1;
466          }
467          else 
468          {
469            /* note this copies the string to position 1, so that numbers can be mapped to chars easily */
470            strcpy(&pgmParams->ChannelNumberMap[1], str);
471            pgmParams->ChannelNumberMap[0]='_'; 
472          }
473        }
474      }
475     
476      /* Trace length (time): optional */
477      else if (k_its("traceTimes") )
478      {
479        pgmParams->traceStart = k_val();
480        pgmParams->traceEnd = k_val();
481      }
482     
483      /* Peak Search window parameters: optional */
484      else if (k_its("searchWindow") )
485      {
486        pgmParams->peakSearchStart = k_val();
487        pgmParams->peakSearchStartMin = k_val();
488        pgmParams->peakSearchEnd = k_val();
489        pgmParams->peakSearchEndMin = k_val();
490      }
491     
492      /* SNR threshold */
493      else if (k_its("snrThresh") )
494        pgmParams->snrThresh = k_val();
495
496      /* waitTime is in seconds to wait before processing an event */
497      else if (k_its("extraDelay") )
498      {
499        pgmParams->waitTime = k_val();
500      }
501     
502      /* LookAtVersion: optional */
503      else if (k_its("LookAtVersion") )
504      {
505        if ( (str = k_str()) )
506        {
507            if(strcmp(str, "All") == 0 ) {
508                pgmParams->LookAtVersion = vAll;   /* Look at all versions of all events */
509                logit("t", "readConfig: looking at all versions of the events.\n");
510            } else if(strcmp(str, "Prelim") == 0 ) {
511                pgmParams->LookAtVersion = vPrelim;   /* Look only at version Prelim of all events */
512                logit("t", "readConfig: looking only at version Prelim of the events.\n");
513            } else if(strcmp(str, "Rapid") == 0 ) {
514                pgmParams->LookAtVersion = vRapid;   /* Look only at version Rapid of all events */
515                logit("t", "readConfig: looking only at version Rapid of the events.\n");
516            } else if(strcmp(str, "Final") == 0 ) {
517                pgmParams->LookAtVersion = vFinal;   /* Look only at version Final of all events */
518                logit("t", "readConfig: looking only at version Final of the events.\n");
519            } else {
520                logit("e", "readConfig: value for optional parameter LookAtVersion is not valid. Possible values are the string: All, Prelim, Rapid or Final.\n");
521                return -1;
522            }
523        }
524      }
525
526      /* SCNL Selectors: optional */
527      else if (k_its("Add") )
528      {
529        if ( (str = k_str()) )  /* sta */
530        {
531          if ( (newSel = (SCNLSEL *)calloc(1, sizeof(SCNLSEL))) == NULL)
532          {
533            fprintf(stderr, "ReadConfig: out of memory for SCNLSEL\n");
534            return -1;
535          }
536          strncpy(newSel->sta, str, 6);
537          if ( (str = k_str()) )  /* comp */
538          {
539            strncpy(newSel->comp, str, 8);
540            if ( (str = k_str()) )  /* net */
541            {
542              strncpy(newSel->net, str, 8);
543              if ( (str = k_str()) )  /* loc */
544              {
545               strncpy(newSel->loc, str, 3);
546               if (pgmParams->pAdd == (SCNLSEL *)NULL)
547               {
548                 pgmParams->pAdd = newSel;
549                 pAdd = newSel;   /* Leave it pointing at the end of list */
550               }
551               else
552               {
553                 pAdd->next = newSel;
554                 pAdd = newSel;
555               }
556              }
557              else
558              {
559                fprintf(stderr, "ReadConfig: \"Add\" missing 1 of 5 arguments\n");
560                err = -1;
561                free(newSel);
562              }
563            }
564            else
565            {
566              fprintf(stderr, "ReadConfig: \"Add\" missing 2 of 5 arguments\n");
567              err = -1;
568              free(newSel);
569            }
570          }
571          else
572          {
573            fprintf(stderr, 
574                    "ReadConfig: \"Add\" missing 3 of 5 arguments\n");
575            err = -1;
576            free(newSel);
577          }
578        }
579        else
580        {
581          fprintf(stderr, "ReadConfig: \"Add\" missing 4 of 5 arguments\n");
582          err = -1;
583        }
584      }
585
586      /* SCN Deleteions: optional */
587      else if (k_its("Del") )
588      {
589        if ( (str = k_str()) )  /* sta */
590        {
591          if ( (newSel = (SCNLSEL *)calloc(1, sizeof(SCNLSEL))) == NULL)
592          {
593            fprintf(stderr, "ReadConfig: out of memory for SCNLSEL\n");
594            return -1;
595          }
596          strncpy(newSel->sta, str, 6);
597          if ( (str = k_str()) )  /* comp */
598          {
599            strncpy(newSel->comp, str, 8);
600            if ( (str = k_str()) )  /* net */
601            {
602              strncpy(newSel->net, str, 8);
603             if ( (str = k_str()) )  /* loc */
604              {
605                strncpy(newSel->loc, str, 3);
606                if (pgmParams->pDel == (SCNLSEL *)NULL)
607                {
608                  pgmParams->pDel = newSel;
609                  pDel = newSel;   /* Leave it pointing at the end of list */
610                }
611                else
612                {
613                  pDel->next = newSel;
614                  pDel = newSel;
615                }
616              }
617            else
618            {
619              fprintf(stderr, "ReadConfig: \"Del\" missing 1 of 5 arguments\n");
620              err = -1;
621              free(newSel);
622            }
623          }
624            else
625            {
626              fprintf(stderr, "ReadConfig: \"Del\" missing 2 of 5 arguments\n");
627              err = -1;
628              free(newSel);
629            }
630          }
631          else
632          {
633            fprintf(stderr, 
634                    "ReadConfig: \"Del\" missing 3 of 5 arguments\n");
635            err = -1;
636            free(newSel);
637          }
638        }
639        else
640        {
641          fprintf(stderr, "ReadConfig: \"Del\" missing 4 arguments\n");
642          err = -1;
643        }
644      }
645
646      /* Trace Source: optional */
647      else if (k_its( "traceSource" ))
648      {
649        if (pgmParams->traceSource == GM_UNDEF)
650        {                 /* Let command-line take precedence */
651          if ( (str = k_str()) )
652          {
653            if (k_its("waveServer"))
654            {
655              pgmParams->traceSource = GM_TS_WS;
656              if ( (str = k_str()) )
657              {
658                if ( (pgmParams->pWSV = 
659                      (WS_ACCESS *)calloc(1, sizeof(WS_ACCESS))) == NULL)
660                {
661                  logit("e", 
662                        "ReadConfig: out of memory for SERVER\n");
663                  return -1;
664                }
665                if (k_its("File"))
666                {
667                  if ( (str = k_str()) )
668                  {
669                    if ( (pgmParams->pWSV->serverFile = mystrdup(str)) == NULL)
670                    {
671                      logit("e", 
672                            "ReadConfig: out of memory for serverFile\n");
673                      return -1;
674                    }
675                  }
676                  else
677                  {
678                    logit("e", 
679                          "ReadConfig: \"traceSource waveServer file\" missing filename\n");
680                    err = -1;
681                  }
682                }
683                else
684                {
685                  int ws_err;
686                  while(str)
687                  {
688                    if (Add2ServerList(str, pgmParams) < 0)
689                      err = -1;  /* Add2ServerList already complained */
690                    str = k_str();
691                    /* We have to catch the kom error here since we are *
692                     * intentionally trying to read to the end of the   *
693                     * string.                                          */
694                    ws_err = k_err();
695                    if (ws_err == -17 && pgmParams->pWSV->pList != 
696                        (PSERVER) NULL)
697                      continue;
698                    else if (ws_err < 0)
699                    {
700                      logit("e", 
701                            "ReadConfig: Bad <%s> command in <%s>\n\t%s\n",
702                            processor, configfile, k_com());
703                      return -1;
704                    }
705                  }
706                }
707                /* else default waveServer file is "servers" in $EW_PARAMS dir */
708              }
709            }
710          }
711          else
712          {
713            logit("e", "ReadConfig: Missing traceSource argument\n");
714            err = -1;
715          }
716        } /* else already set from command-line */
717      }
718     
719      /* Response Source: optional */
720      else if (k_its("respSource") )
721      {
722        if ( (str = k_str()) )
723        {
724          if (k_its("File") )
725          {
726            if ( (str = k_str()) )
727            {
728              if ( (pgmParams->respDir = mystrdup(str)) == NULL)
729              {
730                logit("e", "ReadConfig: out of memory for respDir\n");
731                return -1;
732              }
733              if ( (str = k_str()) )
734              {
735                if ( (pgmParams->respNameFormat = mystrdup(str)) == NULL)
736                {
737                  logit("e", 
738                        "ReadConfig: out of memory for respNameFormat\n");
739                  free(pgmParams->respDir);
740                  pgmParams->respDir = NULL;
741                  return -1;
742                }
743                pgmParams->respSource = GM_RS_FILE;
744              }
745              else
746              {
747                logit("e", 
748                      "ReadConfig: \"respSource FILE\" missing pz-filename-format\n");
749                err = -1;
750              }
751            }
752            else
753            {
754              logit("e", 
755                    "ReadConfig: \"respSource File\" missing 2 arguments\n");
756              err = -1;
757            }
758          }
759#ifdef EWDB
760          else if (k_its("EWDB") )
761          {
762            pgmParams->respSource = GM_RS_EWDB;
763          }
764#endif
765          else
766          {
767            logit("e", "ReadConfig: unknown \"respSource\" <%s>\n", str);
768            err = -1;
769          }
770        }
771        else
772        {
773          logit("e", "ReadConfig: \"respSource\" missing argument\n");
774          err = -1;
775        }
776      }
777     
778      /* the responses are in meters, from rdseed -pf, convert them to nanometers when read in */
779      else if (k_its("ResponseInMeters") )
780        setResponseInMeters( 1 );
781
782      /* Save Trace: optional */
783      else if (k_its("saveTrace") )
784      {
785        if (pgmParams->saveTrace == GM_UNDEF)
786        {
787          if ( (str = k_str()) )
788          {
789            if (k_its("None") )
790              pgmParams->saveTrace = GM_ST_NO;
791            else if (k_its("SAC") )
792            {
793              pgmParams->saveTrace = GM_ST_SAC;
794              if ( (str = k_str()) )
795              {
796                if ( (pgmParams->sacOutDir = mystrdup(str)) == (char *)NULL)
797                {
798                  logit("e", "readConfig: out of memory for sacOutDir\n");
799                  return -1;
800                } 
801                if ( (str = k_str()) )
802                {
803                  if ( (pgmParams->saveDirFormat = mystrdup(str)) == 
804                       (char *)NULL)
805                  {
806                    logit("e", "readConfig: out of memory for saveDirFormat\n");
807                    return -1;
808                  }
809                  if ( (str = k_str()) )
810                  {
811                    if ( (pgmParams->saveNameFormat = mystrdup(str)) == NULL)
812                    {
813                      logit("e", 
814                            "ReadConfig: out of memory for saveNameFormat\n");
815                      return -1;
816                    }
817                  }
818                  else
819                  {
820                    logit("e", 
821                          "ReadConfig: \"saveTrace SAC\" missing 1 argument\n");
822                    err = -1;
823                  }
824                }
825                else
826                {
827                  logit("e",
828                        "ReadConfig: \"saveTrace SAC\" missing 2 arguments\n");
829                  err = -1;
830                }
831              }
832              else
833              {
834                logit("e",
835                      "ReadConfig: \"saveTrace SAC\" missing 3 arguments\n");
836                err = -1;
837              }
838            }
839            else
840            {
841              logit("e", "ReadConfig: unknown \"saveTrace\" arg <%s>\n", str);
842              err = -1;
843            }
844          }
845          else
846          {
847            logit("e", "ReadConfig: \"saveTrace\" missing argument\n");
848            err = -1;
849          }
850        }
851      }
852     
853
854      /* SCNL Parameters: optional */
855      else if (k_its("SCNLpar") )
856      {
857        if (pgmParams->numSCNLPar >= pgmParams->maxSCNLPar)
858        {
859          pgmParams->maxSCNLPar += 10;
860          if ( (pgmParams->pSCNLPar = 
861                (SCNLPAR *)realloc(pgmParams->pSCNLPar, sizeof(SCNLPAR) *
862                                  pgmParams->maxSCNLPar)) == (SCNLPAR *)NULL)
863          {
864            fprintf(stderr, "ReadConfig: out of memory for %d SCNLPARs\n",
865                    pgmParams->maxSCNLPar);
866            return -1;
867          }
868        }
869        if ( (str = k_str()) == NULL)
870        {
871          fprintf(stderr, "ReadConfig: Bad \"SCNLPar\" command\n");
872          return -1;
873        }
874        strncpy(pgmParams->pSCNLPar[pgmParams->numSCNLPar].sta, str, 
875                TRACE_STA_LEN);
876        if ( (str = k_str()) == NULL)
877        {
878          fprintf(stderr, "ReadConfig: Bad \"SCNLPar\" command\n");
879          return -1;
880        }
881        strncpy(pgmParams->pSCNLPar[pgmParams->numSCNLPar].comp, str, 
882                TRACE_CHAN_LEN);
883        if ( (str = k_str()) == NULL)
884        {
885          fprintf(stderr, "ReadConfig: Bad \"SCNLPar\" command\n");
886          return -1;
887        }
888        strncpy(pgmParams->pSCNLPar[pgmParams->numSCNLPar].net, str,
889                TRACE_NET_LEN);
890        if ( (str = k_str()) == NULL)
891        {
892          fprintf(stderr, "ReadConfig: Bad \"SCNLPar\" command\n");
893          return -1;
894        }
895        strncpy(pgmParams->pSCNLPar[pgmParams->numSCNLPar].loc, str,
896                TRACE_LOC_LEN);
897        dummy = k_val(); /* Throw away the station magnitude correction */
898        pgmParams->pSCNLPar[pgmParams->numSCNLPar].fTaper[0] = k_val();
899        pgmParams->pSCNLPar[pgmParams->numSCNLPar].fTaper[1] = k_val();
900        pgmParams->pSCNLPar[pgmParams->numSCNLPar].fTaper[2] = k_val();
901        pgmParams->pSCNLPar[pgmParams->numSCNLPar].fTaper[3] = k_val();
902        pgmParams->pSCNLPar[pgmParams->numSCNLPar].clipLimit = k_val();
903        pgmParams->pSCNLPar[pgmParams->numSCNLPar].taperTime = k_val();
904        pgmParams->numSCNLPar++;
905      }
906       
907#ifdef EWDB
908      /* Earthworm Database access: optional */
909      else if (k_its("EWDBaccess") )
910      {
911        if ( (str = k_str()) )
912        {
913          if ( (pgmParams->pDBaccess = 
914                (DBACCESS *)calloc(1, sizeof(DBACCESS))) == NULL)
915          {
916            logit("e", "ReadConfig: out of memory for DBACCESS\n");
917            return -1;
918          }
919          if ( (pgmParams->pDBaccess->user = mystrdup(str)) == NULL)
920          {
921            logit("e", "ReadConfig: out of memory for DBA user\n");
922            return -1;
923          }
924          if ( (str = k_str()) )
925          {
926            if ( (pgmParams->pDBaccess->pwd = mystrdup(str)) == NULL)
927            {
928              logit("e", "ReadConfig: out of memory for DBA password\n");
929              return -1;
930            }
931            if (  (str = k_str()) )
932            {
933              if ( (pgmParams->pDBaccess->service = mystrdup(str)) == NULL)
934              {
935                logit("e", "ReadConfig: out of memory for DBA service\n");
936                return -1;
937              }
938            }
939            else
940            {
941              logit("e", 
942                    "ReadConfig: \"EWDBaccess\" missing arguments; 3 required\n");
943              err = -1;
944            }
945          }
946          else
947          {
948            logit("e", 
949                  "ReadConfig: \"EWDBaccess\" missing arguments; 3 required\n");
950            err = -1;
951          }
952        }
953        else
954        {
955          logit("e", 
956                "ReadConfig: \"EWDBaccess\" missing arguments; 3 required\n");
957          err = -1;
958        }
959      }
960#endif     
961
962      /* Earthworm transport stuff */
963      else if (k_its("HeartBeatInterval") )
964      {
965        pgmParams->HeartBeatInterval = k_int();
966        init[4] = 1;       
967      }
968
969      else if (k_its("RingInName") )
970      {
971        if ((str = k_str ()) != NULL)
972        {
973          if( ( pEW->RingInKey = GetKey(str) ) == -1 ) 
974          {
975            logit("e", "ReadConfig:  Invalid input ring name <%s>", str);
976            err = -1;
977          }
978          init[5] = 1;
979        }
980        else
981        {
982          logit("e", "ReadConfig: \"RingInName\" missing argument\n");
983          err = -1;
984        }
985      }
986
987      else if (k_its("RingOutName") )
988      {
989        if ((str = k_str ()) != NULL)
990        {
991          if( ( pEW->RingOutKey = GetKey(str) ) == -1 ) 
992          {
993            logit("e", "ReadConfig:  Invalid output ring name <%s>", str);
994            err = -1;
995          }
996          init[6] = 1;
997        }
998        else
999        {
1000          logit("e", "ReadConfig: \"RingOutName\" missing argument\n");
1001          err = -1;
1002        }
1003      }
1004
1005      else if (k_its ("MyModId")) 
1006      {
1007        if ((str = k_str ()) != NULL)
1008        {
1009          if ( GetModId( str, &pEW->hrtLogo.mod ) != 0 ) 
1010          {
1011            logit("e", "ReadConfig: Invalid module name <%s>", str );
1012            return( -1 );
1013          }
1014          if ( GetLocalInst( &pEW->hrtLogo.instid ) != 0 ) 
1015          {
1016            logit("e", "ReadConfig: error getting local installation id" );
1017            return( -1 );
1018          }
1019          if ( GetType( "TYPE_HEARTBEAT", &pEW->hrtLogo.type ) != 0 ) 
1020          {
1021            logit("e", 
1022          "ReadConfig: Invalid message type <TYPE_HEARTBEAT>; exiting!\n" );
1023            return( -1 );
1024          }
1025          pEW->errLogo.mod = pEW->hrtLogo.mod;
1026          pEW->errLogo.instid = pEW->hrtLogo.instid;
1027          if ( GetType( "TYPE_ERROR", &pEW->errLogo.type ) != 0 ) 
1028          {
1029            logit("e", "ReadConfig: Invalid message type <TYPE_ERROR>" );
1030            return( -1 );
1031          }
1032
1033          pEW->gmLogo.mod =  pEW->hrtLogo.mod;
1034          pEW->gmLogo.instid =  pEW->hrtLogo.instid;
1035          if ( GetType( "TYPE_STRONGMOTIONII", &pEW->gmLogo.type ) != 0)
1036          {
1037            logit("e", "ReadConfig: Invalid msg type <TYPE_STRONGMOTIONII>" );
1038            return( -1 );
1039          }
1040
1041          pEW->ha2kLogo.mod =  pEW->hrtLogo.mod;
1042          pEW->ha2kLogo.instid =  pEW->hrtLogo.instid;
1043
1044          pEW->amLogo.mod =  pEW->hrtLogo.mod;
1045          pEW->amLogo.instid =  pEW->hrtLogo.instid;
1046
1047          pEW->threshLogo.mod =  pEW->hrtLogo.mod;
1048          pEW->threshLogo.instid =  pEW->hrtLogo.instid;
1049        }
1050        init[7] = 1;
1051      }
1052      else if (k_its("getEventsFrom") )
1053      {
1054        MSG_LOGO *tLogo = NULL;
1055        tLogo = (MSG_LOGO *)realloc( pEW->GetLogo, (pEW->nGetLogo+1) * 
1056                                     sizeof(MSG_LOGO));
1057        if( tLogo == NULL )
1058        {
1059          logit("e", "ReadConfig: getEventsFrom: error reallocing"
1060                " %zu bytes; exiting!\n",
1061                (pEW->nGetLogo+1)*sizeof(MSG_LOGO) );
1062          return( -1 );
1063        }
1064        pEW->GetLogo = tLogo;
1065        if ((str = k_str ()) != NULL)
1066        {
1067          if ( GetInst( str, &(pEW->GetLogo[pEW->nGetLogo].instid) ) != 0 )
1068          {
1069            logit("e", "ReadConfig: getEventsFrom: invalid installation `%s'\n",
1070                  str );
1071            return( -1 );
1072          }
1073        }
1074        if( ( str = k_str() ) != NULL )
1075        {
1076          if ( GetModId( str, &(pEW->GetLogo[pEW->nGetLogo].mod) ) != 0 )
1077          {
1078            logit("e", "ReadConfig: getEventsFrom: invalid module id `%s'\n",
1079                  str );
1080            return( -1 );
1081          }
1082        }
1083        if ( GetType( "TYPE_HYP2000ARC", &(pEW->GetLogo[pEW->nGetLogo].type) ) != 0 )
1084        {
1085          logit("e", "ReadConfig: getEventsFrom: invalid msgtype `%s'\n", 
1086                "TYPE_HYP2000ARC");
1087          return( -1 );
1088        }
1089        pEW->ha2kLogo.type = pEW->GetLogo[pEW->nGetLogo].type;
1090        pEW->nGetLogo++;
1091        init[8] = 1;
1092      }
1093       
1094      /* Optional: wave_server timeout */
1095      else if (k_its("wsTimeout") )
1096      {
1097        pgmParams->wsTimeout = k_int();
1098      }
1099
1100      /* Optional XML stuff */
1101      else if (k_its( "XMLDir" ) )
1102      {
1103        if ( (str = k_str()) )
1104        {
1105          if ( (pgmParams->XMLDir = mystrdup(str)) == NULL)
1106          {
1107            logit("e", "ReadConfig: out of memory for XMLDir\n");
1108            return -1;
1109          }
1110        }
1111        else
1112        {
1113          fprintf( stderr, "gmew: Bad <XMLDir> command in <%s>;"
1114                   " exiting!\n", configfile );
1115          err = -1;
1116        }
1117      }
1118      else if (k_its( "TempDir" ) )
1119      {
1120        if ( (str = k_str()) )
1121        {
1122          if ( ( pgmParams->TempDir = mystrdup(str)) == NULL)
1123          {
1124            logit("e", "ReadConfig: out of memory for TempDir\n");
1125            return -1;
1126          }
1127        }
1128        else
1129        {
1130          fprintf( stderr, "gmew: Bad <TempDir> command in <%s>;"
1131                   " exiting!\n", configfile );
1132          err = -1;
1133        }
1134      }
1135      else if (k_its( "MappingFile" ) )
1136      {
1137        if ( (str = k_str()) )
1138        {
1139          if ( ( pgmParams->MappingFile = mystrdup(str)) == NULL)
1140          {
1141            logit("e", "ReadConfig: out of memory for MappingFile\n");
1142            return -1;
1143          }
1144        }
1145        else
1146        {
1147          fprintf( stderr, "gmew: Bad <MappingFile> command in <%s>;"
1148                   " exiting!\n", configfile );
1149          err = -1;
1150        }
1151      }
1152     
1153      /* Optional: debug command */
1154      else if (k_its( "Debug") )
1155      {
1156        pgmParams->debug |= k_int();
1157      }
1158     
1159      /* Optional: Respond to dup SCNs - note location code was ignored otherwise if multiple at a sta */
1160      else if (k_its( "allowDuplicates") )
1161      {
1162        pgmParams->allowDuplicates = 1;
1163      }
1164      /* Optional: send activation requests */
1165      else if (k_its( "sendActivateLogo") )
1166      {
1167      /* get the module ide to use for send activate */
1168        str = k_str();
1169        if ( GetModId( str, &(pEW->amLogo.mod) ) != 0 )
1170        {
1171          logit("e", "ReadConfig: sendActivateLogo: invalid module  string %s\n", str);
1172          return( -1 );
1173        }
1174      }
1175      else if (k_its( "sendActivate") )
1176      {
1177        if ( GetType( "TYPE_ACTIVATE_MODULE", &(pEW->amLogo.type) ) != 0 )
1178        {
1179          logit("e", "ReadConfig: sendAlarm: invalid msgtype `TYPE_ACTIVATE_MODULE'\n");
1180          return( -1 );
1181        }
1182        pgmParams->sendActivate = 1;
1183      }
1184     /* Optional: Respond to thresh alarms */
1185     else if (k_its( "watchForThreshAlert") )
1186     {
1187       MSG_LOGO *tLogo = NULL;
1188       tLogo = (MSG_LOGO *)realloc( pEW->GetLogo, (pEW->nGetLogo+1) * 
1189                                    sizeof(MSG_LOGO));
1190       if( tLogo == NULL )
1191       {
1192         logit("e", "ReadConfig: watchForThreshAlert: error reallocing"
1193               " %zu bytes; exiting!\n",
1194               (pEW->nGetLogo+1)*sizeof(MSG_LOGO) );
1195         return( -1 );
1196       }
1197       pEW->GetLogo = tLogo;
1198if ( GetInst( "INST_WILDCARD", &(pEW->GetLogo[pEW->nGetLogo].instid) ) != 0 )
1199{
1200  logit("e", "ReadConfig: watchForThreshAlert: invalid installation `INST_WILDCARD'\n");
1201  return( -1 );
1202}
1203   if ( GetModId( "MOD_WILDCARD", &(pEW->GetLogo[pEW->nGetLogo].mod) ) != 0 )
1204       {
1205         logit("e", "ReadConfig: watchForThreshAlert: invalid module id `MOD_WILDCARD'\n");
1206         return( -1 );
1207       }
1208       if ( GetType( "TYPE_THRESH_ALERT", &(pEW->GetLogo[pEW->nGetLogo].type) ) != 0 )
1209       {
1210         logit("e", "ReadConfig: watchForThreshAlert: invalid msgtype `TYPE_THRESH_ALERT'\n");
1211         return( -1 );
1212       }
1213       pEW->threshLogo.type = pEW->GetLogo[pEW->nGetLogo].type;
1214        str = k_str();
1215        if ( str ) {
1216                pgmParams->threshDuration = atoi( str );
1217                if ( pgmParams->threshDuration <= 0 ) {
1218                        logit("e", "ReadConfig: watchForThreshAlert: invalid duration '%s'; ignoring\n",
1219                                str );
1220                        pgmParams->threshDuration = 0;
1221                }
1222        } else {
1223            k_err();    /* Clear the error of not finding a duration argument */
1224                pgmParams->threshDuration = 20;
1225        }
1226       pEW->nGetLogo++;
1227     }
1228     /* Optional: Respond to activation requests */
1229      else if (k_its( "watchForAlarm") )
1230      {
1231        MSG_LOGO *tLogo = NULL;
1232        tLogo = (MSG_LOGO *)realloc( pEW->GetLogo, (pEW->nGetLogo+1) * 
1233                                     sizeof(MSG_LOGO));
1234        if( tLogo == NULL )
1235        {
1236          logit("e", "ReadConfig: watchForAlarm: error reallocing"
1237                " %zu bytes; exiting!\n",
1238                (pEW->nGetLogo+1)*sizeof(MSG_LOGO) );
1239          return( -1 );
1240        }
1241        pEW->GetLogo = tLogo;
1242            if ( GetInst( "INST_WILDCARD", &(pEW->GetLogo[pEW->nGetLogo].instid) ) != 0 )
1243            {
1244                  logit("e", "ReadConfig: watchForAlarm: invalid installation `INST_WILDCARD'\n");
1245                  return( -1 );
1246            }
1247        if ( GetModId( "MOD_WILDCARD", &(pEW->GetLogo[pEW->nGetLogo].mod) ) != 0 )
1248        {
1249          logit("e", "ReadConfig: watchForAlarm: invalid module id `MOD_WILDCARD'\n");
1250          return( -1 );
1251        }
1252        if ( GetType( "TYPE_ACTIVATE_MODULE", &(pEW->GetLogo[pEW->nGetLogo].type) ) != 0 )
1253        {
1254          logit("e", "ReadConfig: watchForAlarm: invalid msgtype `TYPE_ACTIVATE_MODULE'\n");
1255          return( -1 );
1256        }
1257        pEW->amLogo.type = pEW->GetLogo[pEW->nGetLogo].type;
1258        str = k_str();
1259        if ( str ) {
1260                pgmParams->alarmDuration = atoi( str );
1261                if ( pgmParams->alarmDuration <= 0 ) {
1262                        logit("e", "ReadConfig: watchForAlarm: invalid duration '%s'; ignoring\n",
1263                                str );
1264                        pgmParams->alarmDuration = 0;
1265                }
1266        } else
1267                pgmParams->alarmDuration = 60;
1268        pEW->nGetLogo++;
1269      }
1270     
1271      /* Optional: additional spectral response frequency */
1272      else if (k_its( "AddSpectraResponseAt") )
1273      {
1274        addSR2list( k_val() );
1275          }
1276
1277      /* Optional: additional spectral response frequency */
1278      else if (k_its( "PreTriggerSeconds") )
1279      {
1280        pgmParams->preTriggerSeconds = k_int();
1281          }
1282
1283      else if( t_com()      ) processor = "t_com";
1284
1285      /* Unknown command */ 
1286      else 
1287      {
1288        fprintf(stderr, "ReadConfig: <%s> Unknown command in <%s>.\n", 
1289                com, configfile);
1290        continue;
1291      }
1292
1293      /* See if there were any errors processing the command */
1294      if (k_err ()) 
1295      {
1296        fprintf(stderr, 
1297                "gma: Bad <%s> command in <%s>\n\t%s\n",
1298                processor, configfile, k_com());
1299        return -1;
1300      }
1301
1302    } /** while k_rd() **/
1303
1304    nfiles = k_close ();
1305
1306  } /** while nfiles **/
1307
1308 
1309  if ( pgmParams->alarmDuration ) {
1310        /* WatchForAlarm present, so might not need to handle HYP2000ARC messages */
1311        if ( !init[0] || !init[2] ) {
1312                fprintf( stderr, "Warning: program cannot respond to HYP2000ARC messages:\n" );
1313                if ( !init[0] )
1314                        fprintf( stderr, "\tmissing <staLoc> command\n");
1315                if ( !init[0] )
1316                        fprintf( stderr, "\tmissing <maxDist> command\n");
1317                /* Make it look like these have been supplied */
1318                init[0] = init[2] = 1;
1319        }
1320  }
1321 
1322  /* After all files are closed, check init flags for missed commands */
1323  nmiss = 0;
1324  for (i = 0; i < NUMREQ; i++) 
1325    if (!init[i]) 
1326      nmiss++;
1327
1328  if (nmiss) 
1329  {
1330    fprintf(stderr, "gma: ERROR, no ");
1331    if (!init[0])  fprintf(stderr, "<staLoc> ");
1332    if (!init[1])  fprintf(stderr, "<maxSta> ");
1333    if (!init[2])  fprintf(stderr, "<maxDist> ");
1334    if (!init[3])  fprintf(stderr, "<maxTrace> ");
1335    if (!init[4])  fprintf(stderr, "<HeartBeatInterval> ");
1336    if (!init[5])  fprintf(stderr, "<RingInName> ");
1337    if (!init[6])  fprintf(stderr, "<RingOutName> ");
1338    if (!init[7])  fprintf(stderr, "<MyModId> ");
1339    if (!init[8])  fprintf(stderr, "<getEventsFrom> ");
1340   
1341    fprintf(stderr, "command(s) in <%s>; exitting!\n", configfile);
1342    return -1;
1343  }
1344
1345  /* Sort the SCNLPAR array to make searching more efficient */
1346  if (pgmParams->numSCNLPar > 0)
1347    qsort(pgmParams->pSCNLPar, pgmParams->numSCNLPar, sizeof(SCNLPAR), 
1348          CompareSCNLPARs);
1349
1350  /* If no spectra periods defined, use the old hard-coded ones */
1351  checkSRlist();
1352 
1353  return err;
1354}
1355
1356static void initGM(GMPARAMS *pgmParams)
1357{
1358  pgmParams->peakSearchStart = 0.0;
1359  pgmParams->peakSearchStartMin = 2.0;
1360  pgmParams->peakSearchEnd = 0.0;
1361  pgmParams->peakSearchEndMin = 30.0;
1362  pgmParams->traceStart = 5.0;
1363  pgmParams->traceEnd = 60.0; 
1364  pgmParams->pAdd = NULL;
1365  pgmParams->pDel = NULL;
1366  pgmParams->pSCNLPar = NULL;
1367  pgmParams->pWSV = NULL;      /* assign default "servers" file later */
1368  pgmParams->HeartBeatInterval = 0;
1369  pgmParams->debug = 0;
1370  pgmParams->maxSCNLPar = 0;
1371  pgmParams->maxSta = 0;
1372  pgmParams->numSCNLPar = 0;
1373  pgmParams->snrThresh = 3.0;
1374  pgmParams->respSource = GM_UNDEF;
1375  pgmParams->saveTrace = GM_UNDEF;
1376  pgmParams->staLoc = GM_UNDEF;
1377  pgmParams->traceSource = GM_UNDEF;
1378  pgmParams->wsTimeout = 5000; 
1379  pgmParams->eventID = NULL;
1380  pgmParams->respDir = NULL;
1381  pgmParams->respNameFormat = NULL;
1382  pgmParams->saveNameFormat = NULL;
1383  pgmParams->staLocFile = NULL;
1384  pgmParams->TempDir = NULL;
1385  pgmParams->XMLDir = NULL;
1386  pgmParams->MappingFile = NULL;
1387  pgmParams->pEW->nGetLogo = 0;
1388  pgmParams->pEW->GetLogo = (MSG_LOGO *)NULL;
1389  pgmParams->pEW->RingInKey = 0l;
1390  pgmParams->pEW->RingOutKey = 0l;
1391  pgmParams->pEW->ha2kLogo.type = 0;
1392  pgmParams->pEW->amLogo.type = 0;
1393  pgmParams->pEW->threshLogo.type = 0;
1394  pgmParams->preTriggerSeconds = 10;
1395  pgmParams->ChannelNumberMap[0]=0; /* map 1 2 3 channel cars to N E and Z respecitvely */
1396  return;
1397}
Note: See TracBrowser for help on using the repository browser.