diff --git a/ALH.bit b/ALH.bit new file mode 100644 index 0000000..661b2f5 --- /dev/null +++ b/ALH.bit @@ -0,0 +1,31 @@ +#define AH_width 49 +#define AH_height 48 +unsigned char AH_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, + 0x40, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x40, 0x20, 0x00, 0x00, 0x00, + 0x50, 0x10, 0x40, 0x20, 0x00, 0x00, 0x00, 0x50, 0x10, 0x40, 0x20, 0x00, + 0x00, 0x00, 0x88, 0x10, 0x40, 0x20, 0x00, 0x00, 0x00, 0x88, 0x10, 0xc0, + 0x3f, 0x00, 0x00, 0x00, 0xfc, 0x11, 0x40, 0x20, 0x00, 0x00, 0x00, 0x04, + 0x11, 0x40, 0x20, 0x00, 0x00, 0x00, 0x02, 0x12, 0x40, 0x20, 0x00, 0x00, + 0x00, 0x02, 0x12, 0x40, 0x20, 0x00, 0x00, 0x00, 0x02, 0xf2, 0x4f, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x04, 0x40, 0x08, 0x00, 0x00, 0x80, 0x10, 0x02, 0x80, 0x10, + 0x02, 0x00, 0xc4, 0x10, 0x02, 0x80, 0x10, 0x46, 0x00, 0x42, 0x08, 0x01, + 0x00, 0x21, 0x84, 0x00, 0x42, 0x08, 0x81, 0x03, 0x21, 0x84, 0x00, 0x42, + 0x08, 0x81, 0x03, 0x21, 0x84, 0x00, 0x42, 0x08, 0x81, 0x03, 0x21, 0x84, + 0x00, 0x42, 0x08, 0x01, 0x00, 0x21, 0x84, 0x00, 0xc4, 0x10, 0x02, 0x80, + 0x10, 0x46, 0x00, 0x80, 0x10, 0x02, 0x80, 0x10, 0x02, 0x00, 0x00, 0x20, + 0x04, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..31104b4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,64 @@ +Copyright (c) 2002 University of Chicago. All rights reserved. + +ALH is distributed subject to the following license conditions: + + SOFTWARE LICENSE AGREEMENT + Software: Alarm Handler (ALH) + + 1. The "Software", below, refers to ALH (in either source code, or + binary form and accompanying documentation). Each licensee is + addressed as "you" or "Licensee." + + 2. The copyright holders shown above and their third-party licensors + hereby grant Licensee a royalty-free nonexclusive license, subject to + the limitations stated herein and U.S. Government license rights. + + 3. You may modify and make a copy or copies of the Software for use + within your organization, if you meet the following conditions: + a. Copies in source code must include the copyright notice and this + Software License Agreement. + b. Copies in binary form must include the copyright notice and this + Software License Agreement in the documentation and/or other + materials provided with the copy. + + 4. You may modify a copy or copies of the Software or any portion of it, + thus forming a work based on the Software, and distribute copies of + such work outside your organization, if you meet all of the following + conditions: + a. Copies in source code must include the copyright notice and this + Software License Agreement; + b. Copies in binary form must include the copyright notice and this + Software License Agreement in the documentation and/or other + materials provided with the copy; + c. Modified copies and works based on the Software must carry + prominent notices stating that you changed specified portions of + the Software. + + 5. Portions of the Software resulted from work developed under a U.S. + Government contract and are subject to the following license: the + Government is granted for itself and others acting on its behalf a + paid-up, nonexclusive, irrevocable worldwide license in this computer + software to reproduce, prepare derivative works, and perform publicly + and display publicly. + + 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY + OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE + UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR + EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME + ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, + OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE + SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT + THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE + OR THAT ANY ERRORS WILL BE CORRECTED. + + 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR + THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT + OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, + CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, + INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY + REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF + CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR + OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE + POSSIBILITY OF SUCH LOSS OR DAMAGES. diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..5d7b1f2 --- /dev/null +++ b/Makefile @@ -0,0 +1,191 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +# Gemelnschaft (DESY). +# Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +# Strahlung mbH (BESSY). +# Copyright (c) 2002 Southeastern Universities Research Association, as +# Operator of Thomas Jefferson National Accelerator Facility. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# This file is distributed subject to a Software License Agreement found +# in the file LICENSE that is included with this distribution. +#************************************************************************* +# +# Makefile,v 1.16 2007/10/02 19:08:22 jba Exp +# +TOP=../.. +include $(TOP)/configure/CONFIG + +#=========================== +# Debugging options + +ifeq ($(OS_CLASS), Darwin) +GCC_OPT_YES = -O2 +endif + +#HOST_OPT=NO +#DEBUGCMD = purify -first-only -chain-length=40 -max_threads=256 \ + -always-use-cache-dir -cache-dir=$(shell $(PERL) $(TOP)/config/fullPathName.pl .) +#DEBUGCMD = purify -first-only -chain-length=40 -max_threads=256 \ +# -always-use-cache-dir -cache-dir=$(shell $(PERL) $(TOOLS)/fullPathName.pl .) + +#============================= + +I_WANT_CDEV = NO +I_WANT_GREETINGS = NO +I_WANT_CMLOG = NO + +# These should really be done in /config/RELEASE, but +# defining things here overrides these values. +#CMLOG=/opt/OPI/cmlog +##EPICS_BASE=/home/controls/epics/baseR3.13.1 +#CDEV_DIR = /home/phoebus6/JBA/jlab/cdev1-7 +#CDEVINCLUDE = $(CDEV_DIR)/include +#CDEVLIB = $(CDEV_DIR)/lib/$(HOST_ARCH) + +ifeq ($(I_WANT_GREETINGS),YES) +alh_CFLAGS += -DIWantGreetings +alh_SRCS += productDescriptionShell.c +endif + +ifeq ($(DEBUG), YES) + USR_CCFLAGS += -DDEBUG +endif + +Linux_CPPFLAGS += -D_SVID_SOURCE -D_BSD_SOURCE +printer_CPPFLAGS += $($(OS_CLASS)_CPPFLAGS) +file_CPPFLAGS += $($(OS_CLASS)_CPPFLAGS) +alLog_CPPFLAGS += $($(OS_CLASS)_CPPFLAGS) + +ifeq ($(I_WANT_CMLOG),YES) + CMLOG_BIN = $(CMLOG)/bin/$(HOST_ARCH) + alLog_CFLAGS += -I$(CMLOG)/include -DCMLOG + file_CFLAGS += -I$(CMLOG)/include -DCMLOG + awAlh_CFLAGS += -DCMLOG -DCMLOG_CONFIG="\"cmlogrc.ALH\"" \ + -DCMLOG_BROWSER="\"$(CMLOG_BIN)/cmlog -xrm '*geometry: 1400x500' -c\"" + alh_LIBS += cmlog + cmlog_DIR = $(CMLOG)/lib/$(HOST_ARCH) + # Use following line if cmlog_DIR not in LD_LIBRARY_PATH + USR_LDFLAGS_solaris = -R$(cmlog_DIR) + + LINK.c = $(LINK.cc) + CPLUSPLUS = CCC +endif + +.PHONY: libcmlog.a + +ifeq ($(I_WANT_CDEV),YES) + + CDEV_LIB = $(CDEVLIB) + CDEV_INC = $(CDEVINCLUDE) + + #USR_CXXFLAGS += -g + #USR_CXXFLAGS += -D__STDC__ + #USR_LDFLAGS += -Wl,-E + + USR_CXXFLAGS += -features=no%conststrings + USR_CXXFLAGS += -I$(CDEV_INC) + + PROD_LIBS_DEFAULT += caService cdev + cdev_DIR = $(CDEV_LIB) + caService_DIR = $(CDEV_LIB) + +ifeq ($(ANSI), GCC) + PROD_LIBS += EpicsCa ca + EpicsCa_DIR = $(CDEV_LIB) +endif + SYS_PROD_LIBS_DEFAULT += y l + + alh_SRCS += alCaCdev.cc +else + PROD_LIBS += ca + + alh_SRCS += alCA.c +endif + +USR_INCLUDES += -I../os/$(OS_CLASS) -I../os/default + +#USR_INCLUDES += -I/usr/contrib/X11R5/include -I$(MOTIF_INC) -I$(X11_INC) +USR_INCLUDES += -I$(MOTIF_INC) -I$(X11_INC) + +# baseR3.13.0.beta12 and later +awAlh_CFLAGS += -DALH_HELP_URL="\"http://www.aps.anl.gov/asd/controls/epics/EpicsDocumentation/ExtensionsManuals/AlarmHandler/ALHUserGuide/ALHUserGuide.html\"" + +USER_VPATH += ../os/$(OS_CLASS) +USER_VPATH += ../os/default + +alh_SRCS += acknowledge.c +alh_SRCS += alAudio.c +alh_SRCS += alarm.c +alh_SRCS += alCaCommon.c +alh_SRCS += alConfig.c +alh_SRCS += alFilter.c +alh_SRCS += alLib.c +alh_SRCS += alLog.c +alh_SRCS += alView.c +alh_SRCS += alh.c +alh_SRCS += awAct.c +alh_SRCS += awAlh.c +alh_SRCS += awEdit.c +alh_SRCS += awView.c +alh_SRCS += axArea.c +alh_SRCS += axRunW.c +alh_SRCS += axSubW.c +alh_SRCS += browser.c +alh_SRCS += current.c +alh_SRCS += dialog.c +alh_SRCS += file.c +alh_SRCS += force.c +alh_SRCS += guidance.c +alh_SRCS += heartbeat.c +alh_SRCS += help.c +alh_SRCS += line.c +alh_SRCS += mask.c +alh_SRCS += process.c +alh_SRCS += property.c +alh_SRCS += scroll.c +alh_SRCS += showmask.c +alh_SRCS += sllLib.c +alh_SRCS += beepSevr.c +alh_SRCS += noAck.c + +alh_DB_SRCS = alh_DB.c + +alh_printer_SRCS = printer.c + +PROD_HOST_DEFAULT = alh alh_printer +PROD_HOST_WIN32 = alh + +WIN32_RUNTIME=MD +USR_CFLAGS_WIN32 += /DWIN32 /D_WINDOWS +ifndef BORLAND +USR_LDFLAGS_WIN32 += /SUBSYSTEM:WINDOWS +endif + +PROD_LIBS += Com +PROD_LIBS_DEFAULT += Xmu Xm Xt X11 +PROD_LIBS_Linux += Xmu Xm Xt X11 Xp +PROD_LIBS_Darwin += Xmu Xm Xt X11 + +PROD_LIBS_WIN32 += $(EXCEED_XLIBS) +SYS_PROD_LIBS_WIN32 += winmm user32 +USR_CFLAGS_WIN32 += $(EXCEED_CFLAGS) + +SYS_PROD_LIBS_solaris += socket nsl + +Xmu_DIR = $(X11_LIB) +#Xmu_DIR = /usr/contrib/X11R6/lib +Xm_DIR = $(MOTIF_LIB) +Xt_DIR = $(X11_LIB) +X11_DIR = $(X11_LIB) +Xp_DIR = $(MOTIF_LIB) + +RCS_WIN32 += alh.rc + +include $(TOP)/configure/RULES + +alh.res:../alh.ico +alh.res:../version.h + diff --git a/README.1st b/README.1st new file mode 100644 index 0000000..60ebbdd --- /dev/null +++ b/README.1st @@ -0,0 +1,2 @@ +The extension distribution file should be unziped and untared +in the extensions/src directory. diff --git a/README.CMLOG b/README.CMLOG new file mode 100644 index 0000000..ecce6af --- /dev/null +++ b/README.CMLOG @@ -0,0 +1,139 @@ + ========================================= + == CMLOG Support for the Alarm Handler == + ========================================= + +Ralph Lange + +== README.CMLOG,v 1.1 1999/08/13 19:44:36 lange Exp == + + +Introduction +------------ + +CMLOG is a distributed message logging system developed at JLab (see +http://www.jlab.org/~chen/cmlog/docs/cmlog.html for a complete +description). + +The Alarm Handler can be compiled to support logging alarms and operator +modifications into a CMLOG database instead of (or in addition to) +logging into files. + +The CMLOG system must have been installed and set up prior to compiling +the ALH with CMLOG support. + +The CMLOG server must be running and the programs "cmlog_activate", +"cmlogClientD" and "cmlog" must be in the user's PATH before using ALH +with CMLOG support. + + +Compiling ALH with CMLOG Support +-------------------------------- + +1) In Makefile.Host, set + + I_WANT_CMLOG = YES + +and set the variable CMLOG to point to your CMLOG installation. (The +most natural place for this would be the RELEASE file in the config +directory of your extensions tree, though.) + + CMLOG= + +2) Build the Alarm Handler. (Quick test: if CMLOG support is compiled + in, the usage info printed by "alh -help" contains the "-aCM" and + "-oCM" options.) + + +Starting ALH with CMLOG Logging +------------------------------- + +CMLOG usage is enabled by giving the command line options "-aCM" (for +alarms) resp. "-oCM" (for operator modification). CMLOG logging is +independent from file logging, i.e. you have to add "-D" (disable file +logging) if you want your ALH to log only into CMLOG. + +Examples (i.e. how ALH is used at BESSY): + +Overhead display ALHs (running on an X-terminal without keyboard and +mouse) are started like this: + + alh -global -s -S -D -aCM + +All other control room ALHs are started using + + alh -global -D -oCM + +whereas all "private" ALHs outside the control room are started as + + alh -S -D + + +Viewing Alarm and Opmod logs +---------------------------- + +A standard Motif log browser is included in the CMLOG package. There is +a patch for this browser that enhances its ability to be configured +using command line arguments (-> Jie Chen ). ALH uses +these additional features when starting the cmlog browser (there's an +additional option to start the browser in the View menu). + +You may define the command to start the cmlog browser and the +configuration file name within Makefile.Host (look for the definitions +for CMLOG_CONFIG and CMLOG_BROWSER). If the definition for the +configuration file name contains no path, it is assumed to be in ALH's +config file directory. + +cmlogrc.ALH contains a sample browser configuration. + +Note: If you want to include a tag in a browser query, this tag must be +included in the browser configuration --- it does not have to be in the +visible part of the window, though. + + +CMLOG Tags used by ALH +---------------------- + +o Standard tags (set by CMLOG): + + name alh + user user name \ + host host name \ of logging + pid process ID / ALH process + cmlogDispName X display / + cmlogTime log time stamp + +o ALH specific tags (set by ALH): + + verbosity 0: alarm + 1: acknowledge + 2: other operator modifications + + code 1: REGULAR_RECORD (usual record alarm) + 2: CONNECT_ALARM (connection loss alarm) + 5: ACK_CHANNEL (acknowledge alarm for channel) + 6: ACK_GROUP (acknowledge alarms for group) + 7: CHANGE_MASK (change channel mask) + 8: CHANGE_MASK_GROUP (change group mask) + 9: FORCE_MASK (channel PV force) + 10: FORCE_MASK_GROUP (group PV force) + + facility Alarm: alarm log entries + Opmod: operator modification log entries + + status record's STAT field (string) + severity record's SEVR field (string) + device record or group name + message record or group alias + text additional log text + domain ALH domain (alias or name of GROUP NULL) + value record's value (string) + + +Note: Not all log messages contain all of the ALH specific tags. + + +Contact +------- + +I bet there's plenty of room for improvements. So, if you have any +comments, suggestions or bug fixes, please contact me. diff --git a/acknowledge.c b/acknowledge.c new file mode 100644 index 0000000..8c1d68b --- /dev/null +++ b/acknowledge.c @@ -0,0 +1,116 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* acknowledge.c */ + +/************************DESCRIPTION*********************************** + This file contains routines for alarm acknowledgement +**********************************************************************/ + +#include +#include +#include "alh.h" +#include "alLib.h" +#include "line.h" +#include "ax.h" + +extern int _passive_flag; /* Passive flag. Albert */ +extern int _global_flag; +extern int _DB_call_flag; +extern char * alhAlarmSeverityString[]; +extern const char *executionModeString[]; + +/************************************************************* + * channel acknowledgement + ***************************************************************/ +void ackChan(CLINK *clink) +{ + struct chanData *cdata; + + if (clink == NULL) return; + cdata = (struct chanData *)clink->pchanData; + if (cdata->unackSevr == NO_ALARM) return; + + if(_DB_call_flag) alLog2DBAckChan(cdata->name); + + if (_global_flag && !_passive_flag) { + alCaPutGblAck(cdata->chid,&cdata->unackSevr); + if(cdata->ackPVId) alCaPutAckValue(cdata->ackPVId,&cdata->ackPVValue); + } else { + alSetUnackSevChan(clink,NO_ALARM); + } + +} + +/************************************************************* + * group acknowledgement + ***************************************************************/ +static void ackGroup(GLINK *glink) +{ + SLIST *list; + SNODE *pt; + + if (glink == NULL) return; + if (glink->pgroupData->unackSevr == NO_ALARM) return; + + list = &(glink->chanList); + pt = sllFirst(list); + while (pt) { + ackChan((CLINK *)pt); + pt = sllNext(pt); + } + + list = &(glink->subGroupList); + pt = sllFirst(list); + while (pt) { + ackGroup((GLINK *)pt); + pt = sllNext(pt); + } +} + +/*************************************************** + ack_callback +****************************************************/ +void ack_callback(Widget widget, struct anyLine * line, +XmAnyCallbackStruct * cbs) +{ + GLINK *glink; + CLINK *clink; + + ALINK *area; /* We need it in passive mode only; Albert */ + if (_passive_flag) { + XtVaGetValues(widget, XmNuserData, &area, NULL); + createDialog(area->form_main, XmDIALOG_WARNING, + "You can't acknowledge alarms in passive mode.", " "); + return; + } + if (line->linkType == GROUP) { + glink = (GLINK *)(line->link); + if (glink->pgroupData->unackSevr == NO_ALARM) return; + alLogOpModAckMessage(ACK_GROUP,(GCLINK*)glink, + "%s Ack Group (%s)", + executionModeString[_global_flag], + alhAlarmSeverityString[line->unackSevr]); + ackGroup(glink); + } else if (line->linkType == CHANNEL) { + clink = (CLINK *)(line->link); + if (clink->pchanData->unackSevr == NO_ALARM) return; + alLogOpModAckMessage(ACK_CHANNEL,(GCLINK*)clink, + "%s Ack Channel (%s)", + executionModeString[_global_flag], + alhAlarmSeverityString[line->unackSevr]); + ackChan(clink); + } +} + diff --git a/alCA.c b/alCA.c new file mode 100644 index 0000000..e4cea95 --- /dev/null +++ b/alCA.c @@ -0,0 +1,796 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alCA.c */ + +/************************DESCRIPTION*********************************** + This file contains routines for channel access. +**********************************************************************/ + +#include +#include + +#include "ax.h" + +#define DEBUG_CALLBACKS 0 + +/* global variables */ +extern int _global_flag; +extern int _passive_flag; +int toBeConnectedCount = 0; +extern XtAppContext appContext; +static XtIntervalId caTimeoutId = (XtIntervalId) 0; +static unsigned long caDelay = 100; /* ms */ + +/* forward declarations */ +static void alCaNewAlarmEvent(struct event_handler_args args); +static void alCaForcePVValueEvent(struct event_handler_args args); +static void alCaChannelConnectionEvent(struct connection_handler_args args); +static void alCaForcePVConnectionEvent(struct connection_handler_args args); +static void alCaSevrPVConnectionEvent(struct connection_handler_args args); +static void alCaAckPVConnectionEvent(struct connection_handler_args args); +static void alCaAckPVAccessRightsEvent(struct access_rights_handler_args args); +static void alCaChannelAccessRightsEvent(struct access_rights_handler_args args); +static void alCaForcePVAccessRightsEvent(struct access_rights_handler_args args); +static void alCaSevrPVAccessRightsEvent(struct access_rights_handler_args args); +static void alCaUpdate(XtPointer cd, XtIntervalId * id); +static void alCaException(struct exception_handler_args args); +static void alCaHeartbeatPVAccessRightsEvent(struct access_rights_handler_args args); +static void alCaHeartbeatPVConnectionEvent(struct connection_handler_args args); + + +/********************************************************************* + alCaPend + *********************************************************************/ +void alCaPend(double waitSeconds) +{ + time_t startTime, currentTime; + + currentTime = time(&startTime); + while (toBeConnectedCount > 0 && difftime(currentTime, startTime) < waitSeconds) { + ca_pend_event(.1); + time(¤tTime); + } +} + +/********************************************************************* + alCaIsConnected + *********************************************************************/ +short alCaIsConnected(chid chid) +{ + if (!chid) return FALSE; + if (ca_field_type(chid) == TYPENOTCONN) return FALSE; + else return TRUE; +} + +/********************************************************************* + alCaFlushIo + *********************************************************************/ +void alCaFlushIo() +{ + ca_flush_io(); +} + +/********************************************************************* + init ca, add excptn handler, reg fd, add timer proc + *********************************************************************/ +void alCaInit() +{ + int status; + +#if DEBUG_CALLBACKS + { + printf("alCaInit: caTimeoutId=%d\n", caTimeoutId); + } +#endif + + /* Initialize channel access */ + status = ca_task_initialize(); + if (status != ECA_NORMAL){ + errMsg("ca_task_initialize failed: Return status: %s\n",ca_message(status)); + } + + /* Register exception handler */ + status = ca_add_exception_event(alCaException, NULL); + if (status != ECA_NORMAL){ + errMsg("ca_add_exception_event failed: Return status: %s\n",ca_message(status)); + } + + /* Register file descriptor callback */ + status = ca_add_fd_registration(registerCA, NULL); + if (status != ECA_NORMAL){ + errMsg("ca_add_fd_registration failed: Return status: %s\n",ca_message(status)); + } + + /* Start the CA poll and update areas timer proc */ + caTimeoutId = XtAppAddTimeOut(appContext, caDelay, alCaUpdate, NULL); + +#if DEBUG_CALLBACKS + printf(" caTimeoutId=%d\n", caTimeoutId); +#endif +} + +/********************************************************************* + Callback when there is activity on a CA file descriptor + *********************************************************************/ +void alCaPoll() +{ + +#if DEBUG_CALLBACKS + { + static int n = 0; + + printf("alCaPoll: n=%d\n", n++); + } +#endif + + ca_poll(); +} + +/********************************************************************* + cancel timer, close channel access + *********************************************************************/ +void alCaStop() +{ + int status; + + /* cancel timeout */ + if (caTimeoutId) { + XtRemoveTimeOut(caTimeoutId); + caTimeoutId = (XtIntervalId) 0; + } + /* and close channel access */ + status = ca_task_exit(); + if (status != ECA_NORMAL){ + errMsg("ca_task_exit failed: Return status: %s\n",ca_message(status)); + } +} + +/********************************************************************* + create chid, start search, add connection event handler, add puser, + add access_rights event handler + *********************************************************************/ +void alCaConnectChannel(char *name, chid * pchid, void *puser) +{ + int status; + + if (strlen(name) <= (size_t) 1) return; + + toBeConnectedCount++; + status = ca_search_and_connect(name, pchid, alCaChannelConnectionEvent, puser); + if (status != ECA_NORMAL) { + errMsg("ca_search_and_connect failed for PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } + + status = ca_replace_access_rights_event(*pchid, alCaChannelAccessRightsEvent); + if (status != ECA_NORMAL) { + errMsg("ca_replace_access_rights_event failed for PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } +} + +/********************************************************************* + create chid, start search, add connection event handler, add puser, + add access_rights event handler + *********************************************************************/ +void alCaConnectForcePV(char *name, chid * pchid, void *puser) +{ + int status; + + if (strlen(name) <= (size_t) 1) return; + + toBeConnectedCount++; + status = ca_search_and_connect(name, pchid, alCaForcePVConnectionEvent, puser); + if (status != ECA_NORMAL){ + errMsg("ca_search_and_connect failed for Force PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } + status = ca_replace_access_rights_event(*pchid, alCaForcePVAccessRightsEvent); + if (status != ECA_NORMAL){ + errMsg("ca_replace_access_rights_event failed for Force PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } +} + +/********************************************************************* + create chid, start search, add connection event handler, add puser, + add access_rights event handler + *********************************************************************/ +void alCaConnectSevrPV(char *name, chid * pchid, void *puser) +{ + int status; + + if (strlen(name) <= (size_t) 1) return; + + toBeConnectedCount++; + status = ca_search_and_connect(name, pchid, alCaSevrPVConnectionEvent, puser); + if (status != ECA_NORMAL){ + errMsg("ca_search_and_connect failed for Severity PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } + status = ca_replace_access_rights_event(*pchid, alCaSevrPVAccessRightsEvent); + if (status != ECA_NORMAL){ + errMsg("ca_replace_access_rights_event failed for Severity PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } +} + +/********************************************************************* + create chid, start search, add connection event handler, add puser, + add access_rights event handler + *********************************************************************/ +void alCaConnectHeartbeatPV(char *name, chid * pchid, void *puser) +{ + int status; + + if (strlen(name) <= (size_t) 1) return; + + toBeConnectedCount++; + status = ca_search_and_connect(name,pchid,alCaHeartbeatPVConnectionEvent,puser); + if (status != ECA_NORMAL){ + errMsg("ca_search_and_connect failed for Heartbeat PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } + status = ca_replace_access_rights_event(*pchid, alCaHeartbeatPVAccessRightsEvent); + if (status != ECA_NORMAL){ + errMsg("ca_replace_access_rights_event failed for Heartbeat PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } +} + + +/********************************************************************* +This is similar to previous function alCaConnectSevrPV + *********************************************************************/ +void alCaConnectAckPV(char *name, chid * pchid, void *puser) +{ + int status; + if (strlen(name) <= (size_t) 1) return; + + + toBeConnectedCount++; + status = ca_search_and_connect(name, pchid, alCaAckPVConnectionEvent, puser); + if (status != ECA_NORMAL){ + errMsg("ca_search_and_connect failed for Acknowledge PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } + status = ca_replace_access_rights_event(*pchid, alCaAckPVAccessRightsEvent); + if (status != ECA_NORMAL){ + errMsg("ca_replace_access_rights_event failed for Acknowledge PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } +} + +/********************************************************************* + clear a channel chid + *********************************************************************/ +void alCaClearChannel(chid * pchid) +{ + int status; + + if (!*pchid) return; + + status = ca_clear_channel(*pchid); + if (status != ECA_NORMAL){ + errMsg("ca_clear_channel failed for PV %s " + "Return status: %s\n",ca_name(*pchid),ca_message(status)); + } + *pchid = NULL; +} + + +/********************************************************************* + clear event + *********************************************************************/ +void alCaClearEvent(evid * pevid) +{ + int status; + + if (!*pevid) return; + + status = ca_clear_event(*pevid); + if (status != ECA_NORMAL){ + errMsg("ca_clear_event failed for PV " + "Return status: %s\n",ca_message(status)); + } + *pevid = NULL; +} + +/********************************************************************* + add channel alarm event handler + *********************************************************************/ +void alCaAddEvent(chid chid, evid * pevid, void *clink) +{ + int status; + + if (!chid) return; + + status = ca_add_masked_array_event(DBR_STSACK_STRING, 1, + chid, + alCaNewAlarmEvent, + clink, + (float) 0, (float) 0, (float) 0, + pevid, + DBE_ALARM); + if (status != ECA_NORMAL){ + errMsg("ca_add_masked_array_event failed for PV %s " + "Return status: %s\n",ca_name(chid),ca_message(status)); + } +} + +/********************************************************************* + add forcePV value event handler + *********************************************************************/ +void alCaAddForcePVEvent(chid chid, void *userdata, evid * pevid) +{ + int status; + + if (!chid) return; + + status = ca_add_masked_array_event(DBR_DOUBLE, 1, + chid, + alCaForcePVValueEvent, + userdata, + (float) 0, (float) 0, (float) 0, + pevid, + DBE_VALUE); + if (status != ECA_NORMAL){ + errMsg("alCaAddForcePVEvent: ca_add_masked_array_event failed for Force PV %s " + "Return status: %s\n",ca_name(chid),ca_message(status)); + } +} + +/********************************************************************* + send global alarm acknowledgement + *********************************************************************/ +void alCaPutGblAck(chid chid, short *psevr) +{ + int status; + + if (!chid || ca_field_type(chid) == TYPENOTCONN) return; + + if (!_global_flag || _passive_flag) return; + + status = ca_put(DBR_PUT_ACKS, chid, psevr); + if (status != ECA_NORMAL) { + errMsg("alCaPutGblAck: ca_put alarm acknowledgement failed for PV %s " + "Return status: %s\n",ca_name(chid),ca_message(status)); + } +} + + +/********************************************************************* + global modify acknowledge transients fields + *********************************************************************/ +void alCaPutGblAckT(chid chid, short *pstate) +{ + int status; + + if ( !_global_flag ||_passive_flag) return; + + if (!chid || ca_field_type(chid) == TYPENOTCONN) return; + + status = ca_put(DBR_PUT_ACKT, chid, pstate); + if (status != ECA_NORMAL) { + errMsg("alCaPutGblAckT: ca_put acknowledge transients failed for PV %s " + "Return status: %s\n",ca_name(chid),ca_message(status)); + } +} + + +/********************************************************************* + alCaPutSevValue - write severity value to sevrPV + *********************************************************************/ +void alCaPutSevrValue(chid chid, short *psevr) +{ + int status; + +#if DEBUG_CALLBACKS + { + printf("alCaPutSevrValue: name=%s value=%d\n", ca_name(chid), *psevr); + } +#endif + + if (!_global_flag || _passive_flag) return; + + if (!chid || ca_field_type(chid) == TYPENOTCONN) return; + + status = ca_put(DBR_SHORT, chid, psevr); + if (status != ECA_NORMAL) { + errMsg("alCaPutSevrValue: ca_put failed for Severity PV %s " + "Return status: %s\n",ca_name(chid),ca_message(status)); + } +} + + + +/********************************************************************* + This function is the same as prev. but for ackPV record. + *********************************************************************/ +void alCaPutAckValue(chid chid, short *psevr) +{ + int status; +#if DEBUG_CALLBACKS + { + printf("alCaPutAckValue: name=%s value=%d\n", ca_name(chid), *psevr); + } +#endif + if (!chid || ca_field_type(chid) == TYPENOTCONN) return; + +/* status = ca_put(ca_field_type(chid), chid, psevr); */ + status = ca_put(DBR_ENUM, chid, psevr); + + if (status != ECA_NORMAL) { + errMsg("alCaPutAckValue: ca_put failed for Acknowledge PV %s " + "Return status: %s\n",ca_name(chid),ca_message(status)); + } +} + + +/********************************************************************* + alCaPutHeartbeatValue - write to heartbeatPV + *********************************************************************/ +void alCaPutHeartbeatValue(chid chid, short *pvalue) +{ + int status; + + if (!_global_flag || _passive_flag) return; + + if (!chid || ca_field_type(chid) == TYPENOTCONN) return; + + status = ca_put(DBR_SHORT, chid, pvalue); + if (status != ECA_NORMAL) { + errMsg("alCaPutHeartbeatValue: ca_put failed for Heartbeat PV %s " + "Return status: %s\n",ca_name(chid),ca_message(status)); + } +} + + +/********************************************************************* + channel alarm Event + *********************************************************************/ +static void alCaNewAlarmEvent(struct event_handler_args args) +{ + int stat, sevr; + int ackt, acks; + char value[MAX_STRING_SIZE]; + + stat = ((struct dbr_stsack_string *) args.dbr)->status; + sevr = ((struct dbr_stsack_string *) args.dbr)->severity; + acks = ((struct dbr_stsack_string *) args.dbr)->acks; + ackt = ((struct dbr_stsack_string *) args.dbr)->ackt; + + if (stat >= ALARM_NSTATUS) stat = ALARM_NSTATUS-1; + if (stat < 0) stat = 0; + + if (sevr >= ALARM_NSEV) sevr = ALARM_NSEV-1; + if (sevr < 0) sevr = 0; + + if (acks >= ALARM_NSEV) acks = ALARM_NSEV-1; + if (acks < 0) acks = 0; + + if (ackt != TRUE && ackt != FALSE) ackt = TRUE; + + strcpy(value, ((struct dbr_stsack_string *) args.dbr)->value); + + switch (args.status) { + case ECA_NORMAL: + alNewEvent(stat, sevr, acks, ackt, value, args.usr); + break; + default: + errMsg("alCaNewAlarmEvent failed: Return status: %s " + " for PV %s\n",ca_message(args.status),ca_name(args.chid)); + break; + } +} + +/********************************************************************* + channel access_rights event handler + *********************************************************************/ +static void alCaChannelAccessRightsEvent(struct access_rights_handler_args args) +{ + if (ca_field_type(args.chid) == TYPENOTCONN) return; + if (!ca_read_access(args.chid)) { + alNewEvent(NO_READ_ACCESS, ERROR_STATE, 0, -1, "0", ca_puser(args.chid)); + errMsg("No read access for channel %s\n",ca_name(args.chid)); + } + if (!ca_write_access(args.chid) && _global_flag && !_passive_flag) { + alNewEvent(NO_WRITE_ACCESS, ERROR_STATE, 0, -1, "0", ca_puser(args.chid)); + errMsg("No write access for channel %s\n",ca_name(args.chid)); + } +} + + +/********************************************************************* + forcePV access_rights event handler + *********************************************************************/ +static void alCaForcePVAccessRightsEvent(struct access_rights_handler_args args) +{ + if (ca_field_type(args.chid) == TYPENOTCONN) return; + if (!ca_read_access(args.chid)) { + errMsg("No read access for Force PV %s\n",ca_name(args.chid)); + } +} + + +/********************************************************************* + sevrPV access_rights event handler + *********************************************************************/ +static void alCaSevrPVAccessRightsEvent(struct access_rights_handler_args args) +{ + if (ca_field_type(args.chid) == TYPENOTCONN) return; + if (!ca_write_access(args.chid) && _global_flag && !_passive_flag) { + errMsg("No write access for Severity PV %s\n",ca_name(args.chid)); + } +} + + +/********************************************************************* + this is same as previous function but for .DESC-field. + *********************************************************************/ +static void alCaAckPVAccessRightsEvent(struct access_rights_handler_args args) +{ + if (ca_field_type(args.chid) == TYPENOTCONN) return; + if (!ca_write_access(args.chid) && _global_flag && !_passive_flag) { + errMsg("No write access for Acknowledge PV %s\n",ca_name(args.chid)); + } +} + + +/********************************************************************* + heartbeatPV access_rights event handler + *********************************************************************/ +static void alCaHeartbeatPVAccessRightsEvent(struct access_rights_handler_args args) +{ + if (ca_field_type(args.chid) == TYPENOTCONN) return; + if (!ca_write_access(args.chid) && _global_flag && !_passive_flag) { + errMsg("No write access for Heartbeat PV %s\n",ca_name(args.chid)); + alHeartbeatStop(ca_puser(args.chid)); + } else { + alHeartbeatStart(ca_puser(args.chid)); + } +} + + +/********************************************************************* + channel connection event handler + *********************************************************************/ +static void alCaChannelConnectionEvent(struct connection_handler_args args) +{ + if (args.op == CA_OP_CONN_UP) { + toBeConnectedCount--; + alConnectEvent(ca_puser(args.chid)); + if (!ca_read_access(args.chid)) { + alNewEvent(NO_READ_ACCESS, ERROR_STATE, 0, -1, "0", ca_puser(args.chid)); + errMsg("No read access for channel %s\n",ca_name(args.chid)); + } else if (!ca_write_access(args.chid) && _global_flag && !_passive_flag) { + alNewEvent(NO_WRITE_ACCESS, ERROR_STATE, 0, -1, "0", ca_puser(args.chid)); + errMsg("No write access for channel %s\n",ca_name(args.chid)); + } + } else if (args.op == CA_OP_CONN_DOWN) { + alNewEvent(NOT_CONNECTED, ERROR_STATE, 0, -1, "0", ca_puser(args.chid)); + } else { + errMsg("Unknown connection event for channel %s\n",ca_name(args.chid)); + } +} + + +/********************************************************************* + forcePV connection event handler + *********************************************************************/ +static void alCaForcePVConnectionEvent(struct connection_handler_args args) +{ + if (args.op == CA_OP_CONN_UP) { + toBeConnectedCount--; + if (!ca_read_access(args.chid)) { + errMsg("No read access for Force PV %s\n",ca_name(args.chid)); + } + } else if (args.op == CA_OP_CONN_DOWN) { + errMsg("Not Connected: Force PV %s for %s\n", + ca_name(args.chid),(char *)ca_puser(args.chid)); + } else { + errMsg("Unknown connection event Force PV %s for %s\n", + ca_name(args.chid),(char *)ca_puser(args.chid)); + } +} + + +/********************************************************************* + sevrPV connection event handler + *********************************************************************/ +static void alCaSevrPVConnectionEvent(struct connection_handler_args args) +{ + if (args.op == CA_OP_CONN_UP) { + toBeConnectedCount--; + if (!ca_write_access(args.chid) && _global_flag && !_passive_flag) { + errMsg("No write access for Severity PV %s\n",ca_name(args.chid)); + } + } else if (args.op == CA_OP_CONN_DOWN) { + errMsg("Not Connected: Severity PV %s for %s\n", + ca_name(args.chid),(char *)ca_puser(args.chid)); + } else { + errMsg("Unknown connection event Severity PV %s for %s\n", + ca_name(args.chid),(char *)ca_puser(args.chid)); + } +} + +/********************************************************************* + ackPV connection event handler + *********************************************************************/ +static void alCaAckPVConnectionEvent(struct connection_handler_args args) +{ + if (args.op == CA_OP_CONN_UP) { + toBeConnectedCount--; + if (!ca_write_access(args.chid) && _global_flag && !_passive_flag) { + errMsg("No write access for Acknowledge PV %s\n",ca_name(args.chid)); + } + } else if (args.op == CA_OP_CONN_DOWN) { + errMsg("Not Connected: Acknowledge PV %s for %s\n", + ca_name(args.chid),(char *)ca_puser(args.chid)); + } else { + errMsg("Unknown connection event Acknowledge PV %s for %s\n", + ca_name(args.chid),(char *)ca_puser(args.chid)); + } +} + + +/********************************************************************* + heartbeatPV connection event handler + *********************************************************************/ +static void alCaHeartbeatPVConnectionEvent(struct connection_handler_args args) +{ + if (args.op == CA_OP_CONN_UP) { + toBeConnectedCount--; + if (!ca_write_access(args.chid) && _global_flag && !_passive_flag) { + errMsg("No write access for Heartbeat PV %s\n",ca_name(args.chid)); + alHeartbeatStop(ca_puser(args.chid)); + } else { + alHeartbeatStart(ca_puser(args.chid)); + } + } else if (args.op == CA_OP_CONN_DOWN) { + errMsg("Not Connected: Heartbeat PV %s\n",ca_name(args.chid)); + alHeartbeatStop(ca_puser(args.chid)); + } else { + errMsg("Unknown connection event Heartbeat PV %s\n",ca_name(args.chid)); + } +} + + +/********************************************************************* + group forcePV value event handler + *********************************************************************/ +static void alCaForcePVValueEvent(struct event_handler_args args) +{ + if (args.status == ECA_NORMAL) { + alForcePVValueEvent(args.usr, *(double *) args.dbr); + } else { + errMsg("alCaForcePVValueEvent failed: Return status: %s " + " for PV %s\n",ca_message(args.status),ca_name(args.chid)); + } +} + +/********************************************************************* + alCaUpdate -- Timer proc to update screen + *********************************************************************/ +static void alCaUpdate(XtPointer cd, XtIntervalId * id) +{ + +#if DEBUG_CALLBACKS + { + static int n = 0; + + printf("alCaUpdate: n=%d\n", n++); + } +#endif + + ca_poll(); + alUpdateAreas(); + caTimeoutId = XtAppAddTimeOut(appContext, caDelay, alCaUpdate, NULL); +} + +/********************************************************************* + ca exception messages + *********************************************************************/ +static void alCaException(struct exception_handler_args args) +{ +#define MAX_EXCEPTIONS 25 + static int nexceptions = 0; + static int ended = 0; + + if (ended) return; + if (nexceptions++ > MAX_EXCEPTIONS) { + ended = 1; + errMsg("Channel Access Exception: Too many exceptions [%d]\n", + MAX_EXCEPTIONS); + ca_add_exception_event(NULL, NULL); + return; + } + errMsg("Channel Access Exception: %s Context: %s\n", + ca_message(args.stat) ? ca_message(args.stat) : "Unavailable", + args.ctx ? args.ctx : "Unavailable"); +} + + + +static void description_callback (struct event_handler_args args); + +/********************************************************************* + getDescriptionRecord + *********************************************************************/ +void getDescriptionRecord(char *name,char *description,chid descriptionFieldCaId) +{ + int status; + static char desc_name[64]; + memset(desc_name,0,64); + strcpy(desc_name,name); + strcat(desc_name,".DESC"); + + status = ca_search(desc_name, &descriptionFieldCaId); + if (status != ECA_NORMAL) { + SEVCHK(status," CAN'T search description field\n"); + fprintf(stderr,"%s: CAN'T search description field\n",desc_name); + *description=0; + return; + } + + /* status = ca_pend_io(0.5); */ + status = ca_pend_io(5.0); + ca_pend_event(.0001); + if (status != ECA_NORMAL) + { + SEVCHK(status," CAN'T pend description field\n"); + fprintf(stderr,"%s: CAN'T pend description field\n",desc_name); + *description=0; + return; + } + + status = ca_array_get (DBR_STRING,1,descriptionFieldCaId,description); + if (status != ECA_NORMAL) + { + SEVCHK(status," CAN'T get description field\n"); + fprintf(stderr,"%s: CAN'T get description field\n",desc_name); + *description=0; + return; + } + + /* status = ca_pend_io(0.5); */ + status = ca_pend_io(5.0); + ca_pend_event(.0001); + if (status != ECA_NORMAL) + { + SEVCHK(status," CAN'T pend description field again \n"); + fprintf(stderr,"%s: CAN'T pend description field again \n",name); + *description=0; + return; + } + + status=ca_add_event + (DBR_STRING,descriptionFieldCaId,description_callback,description,NULL); + /* status = ca_pend_io(0.5); */ + status = ca_pend_io(5.0); + ca_pend_event(.0001); + +} + +/********************************************************************* + description_callback + *********************************************************************/ +static void description_callback (struct event_handler_args args) +{ + char *string= (char *)args.dbr; + char * descr = (char *)args.usr; + if(strlen(string) > 127) return; /* May be garbage. Avoid overwriting*/ + strcpy(descr,string); +} diff --git a/alCaCdev.cc b/alCaCdev.cc new file mode 100644 index 0000000..979cb31 --- /dev/null +++ b/alCaCdev.cc @@ -0,0 +1,753 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ + +/****************************************************************** + cdev access routines +******************************************************************/ + +#include +#include +#include +#include + +#include + +#include "cdevSystem.h" +#include "cdevRequestObject.h" +#include "cdevDevice.h" +#include "cdevGroup.h" +#include "cdevErrCode.h" +#include "cdevClock.h" + +extern "C" { +#include "alarm.h" +#include "fdmgr.h" +#include "cadef.h" + +#include "ax.h" + +static void alFdmgrAddCdev (int fd, int opened, void *); + +//------------------------------ +// Need the following external definitions +#define GROUP 1 +#define CHANNEL 2 + +#define CA_SERVICE_NAME "caService" + + +//------------------------------ +// Define globals +extern int _global_flag; +extern int _passive_flag; +int toBeConnectedCount = 0; +extern XtIntervalId caTimeoutId=(XtIntervalId)0; +static int cdev_finished = 0; +unsigned long caDelay = 100; /* ms */ + +//------------------------------ +// Define statics +static cdevSystem * systemAlh; +static char buff[511]; + + +//------------------------------ +// forward declarations +static void alCaNewAlarmEvent (int, void *, cdevRequestObject &, cdevData &); +static void alCaForcePVValueEvent (int, void *, cdevRequestObject &, cdevData &); +static void SevrChangeConnEvent (int, void *, cdevRequestObject &, cdevData &); +static void alCaUpdate(XtPointer cd, XtIntervalId *id); + + + +// ========================================================================== +// ========================================================================== +/* cdevSignal + * + * Stores a signal's device/attribute pair, as well as a request + * object for [device "get" attribute]. This request object + * is not used for sending requests, but rather for checking the + * validity of the device/message/attribute combination. One is + * created for each call to alCaSearchName(), and destroyed in + * alCaClearChannel(). + */ +class cdevSignal +{ +private: + char *dev; + char *attr; + cdevRequestObject *req; + +public: + cdevSignal (char *name); + ~cdevSignal (void) { if (dev) free (dev); } + + char *device (void) { return dev; } + char *attribute (void) { return attr; } + cdevRequestObject &request (void) { return *req; } + int connected (void) + { + return (req->getState() == CDEV_STATE_CONNECTED); + } +}; + +/* HP compiler won't inline this member because of iterative construct. */ +cdevSignal::cdevSignal (char *name) +{ + static cdevData dummy; + + attr = dev = strdup (name); + while (*attr && !isspace (*attr)) attr++; + if (*attr) *attr++ = 0; /* terminate dev str and point attr at remainder */ + else attr = "VAL"; + + sprintf (buff, "get %s", attr); + req = cdevRequestObject::attachPtr (dev, buff); + // need to send so that request object attempts to conenct + req->sendNoBlock (0, &dummy); +} + + +// ========================================================================== +// ========================================================================== +/* cdevMonitor + * + * Contains request object and callback associated with a + * device/message pair, along with most recent callback + * status and signal attributes (value, status, severity). + * Enables canceling callbacks --cdev needs the original + * callback object in order to turn off a monitor. + */ +class cdevMonitor +{ +private: + cdevCallback *cb; + cdevSignal *signal; + void *data_; + int cb_status_; // most recent callback status + int status_, severity_; // signal status, severity + +public: + cdevMonitor (cdevSignal *sig) + : cb (0), + signal (sig), + data_ (0), + cb_status_ (CDEV_NOTCONNECTED), + status_ (0), + severity_ (0) + { + // nothing to do here! + } + + ~cdevMonitor (void) { if (cb) delete cb; } + + // start + // + // Sets up a monitorOn connection which will invoke the given + // function on change. The user data argument is contained + // inside this object, which will be supplied as the client + // argument to the callback. Inside the callback function, + // then, the user data will be accessible via the ::data() + // member of this object. + int start (cdevCallbackFunction func, void *d, cdevData &context) + { + cdevRequestObject *request; + + data_ = d; + if (cb) delete cb; + cb = new cdevCallback (func, this); + sprintf (buff, "monitorOn %s", signal->attribute()); + request = cdevRequestObject::attachPtr (signal->device(), buff); + request->setContext (context); + +#ifdef DEBUG + fprintf + (stderr, "sendCallback: device = %s, message = %s\n", + signal->device(), buff); + fflush (stderr); +#endif + + return request->sendCallback (0, *cb); + } + + + // data + // + // Returns the client data argument. + void *data (void) { return data_; } + + + // cb_status + // + // Without an argument, returns a CDEV_XXX value which corresponds + // to the value from the most recent callback. Initial value is + // CDEV_NOT_CONNECTED. With and argument, sets the object's state. + int cb_status (void) { return cb_status_; } + void cb_status (int s) { cb_status_ = s; } + + + // status/severity + // + // Without arguments, these routines return the most recently + // set value for the appropriate property. With, they set + // the associated attribute locally (not in the control-system!). + int status (void) { return status_; } + int severity (void) { return severity_; } + void status (int s) { status_ = s; } + void severity (int s) { severity_ = s; } + + + // stop + // + // Turn off the monitor. + int stop (void) + { + cdevRequestObject *request; + + sprintf (buff, "monitorOff %s", signal->attribute()); + request = cdevRequestObject::attachPtr (signal->device(), buff); + + // Bad business here: can't turn off specific callback. The way + // cdev works presently, in order to turn off a specific monitor + // you have to pass the same cdevCallback object with the same + // device/attribute and the message "monitorOff". This gives + // rise to many potentially nasty errors, however, because the + // cdev service provides no general way for clients to know that + // the callback has finished. + // + // Workaround: + // + // assumption: only one monitorOn request for every device/attribute + // pair. + // method: send "monitorOff" with null callback in order to + // cancel *all* monitors for the device/attribute pair. + + return request->sendNoBlock (0, 0); + // return request->sendCallback (0, *cb); + } +}; + + +extern "C" { +/****************************************************************************** + alCaPend +******************************************************************************/ +void alCaPend (double sec) +{ + static cdevClock timer; + +#ifdef DEBUG + fprintf (stderr, "cdevSystem::poll() for %f seconds\n", sec); + fflush (stderr); +#endif + timer.schedule (0, sec); + while (toBeConnectedCount>0 && !timer.expired()) systemAlh->poll(); +} + +/****************************************************************************** + alCaIsConnected +******************************************************************************/ +short alCaIsConnected(chid chid) +{ + cdevSignal *signal = (cdevSignal *)chid; + + if (!signal) return FALSE; + if (signal->connected()) return TRUE; + else return FALSE; +} + +/****************************************************************************** + alCaFlushIo + ******************************************************************************/ +void alCaFlushIo(char *) +{ +#ifdef DEBUG + fprintf (stderr, "cdevSystem::flush(); cdevSystem::poll()\n"); + fflush (stderr); +#endif + systemAlh->flush(); +} + +/****************************************************************************** + initializes channel access + register channel access file descriptor + ******************************************************************************/ +void alCaInit() +{ + systemAlh = &cdevSystem::defaultSystem(); + systemAlh->setThreshold (CDEV_SEVERITY_ERROR); + systemAlh->addFdChangedCallback (alFdmgrAddCdev, 0); + caTimeoutId = XtAppAddTimeOut(appContext,caDelay,alCaUpdate,NULL); +} + +/****************************************************************************** + perform CA handling when events exist + ******************************************************************************/ +void alCaPoll() +{ + if (systemAlh) + { +#ifdef DEBUG + fprintf (stderr, "cdevSystem::flush(); cdevSystem::poll()\n"); + fflush (stderr); +#endif + /* systemAlh->flush(); shouldn't be needed*/ + systemAlh->poll(); + } +} + +/****************************************************************************** + cancel registration of ca fds, cancel timeout, and exit ca task + ******************************************************************************/ +void alCaStop() +{ + /* cancel timeout */ + if (caTimeoutId) { + XtRemoveTimeOut(caTimeoutId); + caTimeoutId = (XtIntervalId)0; + } + cdev_finished = 1; +} + +/****************************************************************************** + add alarm event handler for a channel + ******************************************************************************/ +void alCaConnectChannel(char *name, chid * pchid, void *) +{ + cdevSignal *signal = new cdevSignal (name); + toBeConnectedCount++; + + if (signal->request().getState() == CDEV_INVALID) + errMsg("alCaConnectChannel: request object is invalid for PV %s\n",name); + *pchid = (chid)signal; +} + +/****************************************************************************** + add alarm event handler for a force PV + ******************************************************************************/ +void alCaConnectForcePV(char *name, chid * pchid, void *) +{ + cdevSignal *signal = new cdevSignal (name); + toBeConnectedCount++; + + if (signal->request().getState() == CDEV_INVALID) + errMsg("alCaConnectForcePV: request object is invalid for force PV %s\n",name); + *pchid = (chid)signal; +} + +/****************************************************************************** + add alarm event handler for a severity PV + ******************************************************************************/ +void alCaConnectSevrPV(char *name, chid * pchid, void *) +{ + cdevSignal *signal = new cdevSignal (name); + toBeConnectedCount++; + + if (signal->request().getState() == CDEV_INVALID) + errMsg("alCaConnectSevrPV: request object is invalid for severity PV %s\n",name); + *pchid = (chid)signal; +} + +/********************************************************************* + alCaConnectHeartbeatPV + *********************************************************************/ +void alCaConnectHeartbeatPV(char *name, chid * pchid, void *puser) +{ + cdevSignal *signal = new cdevSignal (name); + toBeConnectedCount++; + + if (signal->request().getState() == CDEV_INVALID) + errMsg("alCaConnectChannel: request object is invalid for heartbeat PV %s\n",name); + *pchid = (chid)signal; + +} + +/****************************************************************************** + clear a channel chid + ******************************************************************************/ +void alCaClearChannel (chid *pchid) +{ + if (*pchid) delete (cdevSignal *)*pchid; + *pchid = NULL; +} + +/****************************************************************************** + clear event + ******************************************************************************/ +void alCaClearEvent (evid *pevid) +{ + cdevMonitor *monitor = (cdevMonitor *)pevid; + + if (monitor) + { + if (monitor->stop() != CDEV_SUCCESS) + errMsg("alCaClearEvent: error cancelling monitor for %s\n",ca_name((*pevid)->chan)); + delete monitor; + } + *pevid = NULL; +} + +/****************************************************************************** + add New Alarm Event + ******************************************************************************/ +void alCaAddEvent (chid chid, + evid *pevid, + void *clink) +{ + cdevSignal *signal = (cdevSignal *)chid; + cdevMonitor *monitor; + cdevData ctx; + int alarm = 0; + + if (!signal) return; + + // now, if our signal belongs to the channel access service, we + // need to use a different context. + if (strcmp (signal->request().service().name(), CA_SERVICE_NAME) == 0) + { + ctx.insert ("value", 0); + ctx.insert ("severity", 2); + ctx.insert ("status", 2); + } + else + { + ctx.insert ("value", 3); + ctx.insert ("severity", 1); + ctx.insert ("status", 1); + } + + monitor = new cdevMonitor (signal); + alarm = (monitor->start (alCaNewAlarmEvent, clink, ctx) != CDEV_SUCCESS); + // if (!signal->connected() || alarm) + if (alarm) + { +#ifdef DEBUG + if (!signal->connected()) + fprintf (stderr, "%s.%s: not connected\n", + signal->device(), signal->attribute()); + if (alarm) + fprintf (stderr, "%s.%s: error initiating monitor\n", + signal->device(), signal->attribute()); + fflush (stderr); +#endif + alNewEvent (NOT_CONNECTED, ERROR_STATE, 0, -1, "0", clink); + } + + *pevid = (evid)monitor; +} + + +///****************************************************************************** +// add change connection event for sevrPV +// ******************************************************************************/ +//void alCaAddSevrPVEvent (chid, void *) +//{ +// // this doesn't apply to cdev device/attributes --severity is +// // retrieved via tag in callback object. +//} +// +/****************************************************************************** + alCaAddForcePVEvent + ******************************************************************************/ +void alCaAddForcePVEvent (chid chid, + void *userdata, + evid *pevid) +{ + cdevSignal *signal = (cdevSignal *)chid; + cdevMonitor *monitor; + cdevData ctx; + + if (!signal) + { + errMsg("alCaAddForcePVEvent: null cdevSignal pointer\n"); + return; + } + + monitor = new cdevMonitor (signal); + sprintf (buff, "%s %s", signal->device(), signal->attribute()); + + else errMsg ("alCaAddForcePVEvent: Invalid type error\n"); + + ctx.insert ("value", 0); + + if (monitor->start (alCaForcePVValueEvent, userdata, ctx) != CDEV_SUCCESS) + errMsg("alCaAddForcePVEvent: error starting monitor\n"); + + *pevid = (evid)monitor; +} + +/****************************************************************************** + alCaPutGblAck + ******************************************************************************/ +void alCaPutGblAck (chid chid, short *psevr) +{ + cdevSignal *signal = (cdevSignal *)chid; + cdevData out; + + if (!_global_flag || _passive_flag) return; + + if (!signal) + { + errMsg("alCaPutGblAck: null cdevSignal pointer\n"); + return; + } + + sprintf (buff, "ack %s", signal->attribute()); + out.insert ("value", *psevr); + if (signal->request().device().sendNoBlock (buff, out, 0) != CDEV_SUCCESS) + { + sprintf (buff, "%s ack %s", signal->device(), signal->attribute()); + errMsg ("alCaPutGblAck: error sending acknowledgement\n"); + } +} + +/****************************************************************************** + alCaPutGblAckT + ******************************************************************************/ +void alCaPutGblAckT(chid chid, short *pstate) +{ + cdevSignal *signal = (cdevSignal *)chid; + cdevData out; + + if (!_global_flag ||_passive_flag) return; + + if (!signal) + { + errMsg("alCaPutGblAck: null cdevSignal pointer\n"); + return; + } + + sprintf (buff, "ackt %s", signal->attribute()); + out.insert ("value", *pstate); + if (signal->request().device().sendNoBlock (buff, out, 0) != CDEV_SUCCESS) + { + sprintf (buff, "%s ack %s", signal->device(), signal->attribute()); + errMsg ("alCaPutGblAckT: error sending acknowledgement\n"); + } +} + +/****************************************************************************** + alCaPutSevValue + ******************************************************************************/ +void alCaPutSevrValue (chid chid, short *psevr) +{ + cdevSignal *signal = (cdevSignal *)chid; + cdevRequestObject *request; + cdevData out; + + if (!_global_flag || _passive_flag) return; + + if (!signal) + { + errMsg("alCaPutSevrValue: null cdevSignal pointer\n"); + return; + } + + sprintf (buff, "set %s", signal->attribute()); + request = cdevRequestObject::attachPtr (signal->device(), buff); + out.insert ("value", *psevr); + if (request->sendNoBlock (out, 0) != CDEV_SUCCESS) + { + errMsg ("alCaPutSevrValue: error writing severity %s set %s\n", signal->device(), signal->attribute()); + } +} + +/****************************************************************************** + alCaPutHeartbeatValue + ******************************************************************************/ +void alCaPutHeartbeatValue (chid chid, short *pvalue) +{ + cdevSignal *signal = (cdevSignal *)chid; + cdevRequestObject *request; + cdevData out; + + if (!_global_flag || _passive_flag) return; + + if (!signal) + { + errMsg("alCaPutHeartbeatValue: null cdevSignal pointer\n"); + return; + } + + sprintf (buff, "set %s", signal->attribute()); + request = cdevRequestObject::attachPtr (signal->device(), buff); + out.insert ("value", *pvalue); + if (request->sendNoBlock (out, 0) != CDEV_SUCCESS) + { + errMsg ("alCaPutHeartbeatValue: error writing heartbeat value %s set %s\n", signal->device(), signal->attribute()); + } +} + +/****************************************************************************** + * Close connection event +******************************************************************************/ +static void closeConnectionEvent (int, void *, cdevRequestObject &, cdevData &) +{ + // Dont know how to close cdev connection event +} + +} // end extern "C" + +/****************************************************************************** + alCaNewAlarmEvent get channel sevr, status, value + then invoke alNewEvent & update value of SevrPVName +******************************************************************************/ +static void alCaNewAlarmEvent (int status, + void *arg, + cdevRequestObject &req, + cdevData &result) +{ + cdevMonitor *monitor = (cdevMonitor *)arg; + + if (cdev_finished) return; + + sprintf (buff, "%s %s", req.device().name(), req.message()); + +#ifdef DEBUG + fprintf (stderr, "callback: %s\n", buff); + fflush (stderr); +#endif + switch (status) + { + case CDEV_RECONNECTED: + errMsg ("Reconnected (Channel PVname)\n"); + + case CDEV_SUCCESS: + { + char valstr[MAX_STRING_SIZE+1]; + char *pstr; + int sevr; + int stat; + int changed = 0; + + // if this is the first event, let's turn off any associated alarms + if (monitor->cb_status() == CDEV_NOTCONNECTED) + toBeConnectedCount--; + + // hey, cdevData can do the value --> string conversion for us! + if (result.get ("value", valstr, MAX_STRING_SIZE) == CDEV_SUCCESS) + pstr = valstr; + else pstr = "Unknown"; + + if (result.get ("severity", &sevr) == CDEV_SUCCESS) + { + changed = (changed || (monitor->severity() != sevr)); + monitor->severity (sevr); + } + + if (result.get ("status", &stat) == CDEV_SUCCESS) + { + changed = (changed || (monitor->status() != stat)); + monitor->status (stat); + } + + // only call alNewEvent if either the status or severity + // has changed + if (changed) + alNewEvent + (monitor->status(), monitor->severity(), 0, -1, pstr, monitor->data()); + } + break; + + case CDEV_NOACCESS: + { + alNewEvent (NO_READ_ACCESS, ERROR_STATE, 0, -1, "0", monitor->data()); + } + break; + + case CDEV_DISCONNECTED: + { + alNewEvent (NOT_CONNECTED, ERROR_STATE, 0, -1, "0", monitor->data()); + } + break; + + default: + { + alNewEvent (NOT_CONNECTED, ERROR_STATE, 0, -1, "0", monitor->data()); + } + break; + } + + monitor->cb_status (status); +} + +/****************************************************************************** + * ForcePV Value Event Callback +******************************************************************************/ +static void alCaForcePVValueEvent (int status, + void *arg, + cdevRequestObject &req, + cdevData &result) +{ + cdevMonitor *monitor = (cdevMonitor *)arg; + + if (cdev_finished) return; + + switch(status) + { + case CDEV_RECONNECTED: + errMsg("Reconnected (Force Gp PVName) %s--(%s %s)\n", + (char *)monitor->data(), req.device().name(), req.message()); + + case CDEV_SUCCESS: + double value; + + toBeConnectedCount--; + result.get ("value", &value); + alForcePVValueEvent (monitor->data(), value); + break; + + case CDEV_NOACCESS: + errMsg("No read access (Force Gp PVname) %s--(%s %s)\n", + (char *)monitor->data(), req.device().name(), req.message()); + break; + + case CDEV_DISCONNECTED: + errMsg("Not Connected (Force Gp PVName) %s--(%s %s)\n", + (char *)monitor->data(), req.device().name(), req.message()); + break; + + default: + errMsg("Error while monitoring (Force Gp PVName) %s--(%s %s)\n", + (char *)monitor->data(), req.device().name(), req.message()); + break; + } + + monitor->cb_status (status); +} + +/****************************************************************************** + alFdmgrAddCdev +******************************************************************************/ +static void alFdmgrAddCdev (int fd, int opened, void *) +{ + void *pfdctx=0; + registerCA (pfdctx, fd, opened); +} + +/****************************************************************************** + alCaUpdate +******************************************************************************/ +static void alCaUpdate(XtPointer , XtIntervalId *) +{ +#ifdef DEBUG + fprintf (stderr, "cdevSystem::poll()\n"); + fflush (stderr); +#endif + systemAlh->poll(); + alUpdateAreas(); + caTimeoutId = XtAppAddTimeOut(appContext,caDelay,alCaUpdate,NULL); +} + diff --git a/alCaCommon.c b/alCaCommon.c new file mode 100644 index 0000000..4ac4775 --- /dev/null +++ b/alCaCommon.c @@ -0,0 +1,306 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alCaCommon.c */ + +/************************DESCRIPTION*********************************** + This file contains ca routines common to cdev and epics ca. + This file also contains misc group and channel routines. +**********************************************************************/ + +/****************************************************************** + Some misc. routines +******************************************************************/ + +#include +#include + +#include "alarm.h" +#include "fdmgr.h" +#include "cadef.h" + +#include "sllLib.h" +#include "alLib.h" +#include "alh.h" +#include "ax.h" + +extern SLIST *areaList; +extern int toBeConnectedCount; +extern int _transients_flag; +extern int _global_flag; +extern int _passive_flag; +extern int _description_field_flag; + +/* Struct for file descriptor linked list */ +struct FDLIST { + struct FDLIST *prev; + XtInputId inpid; + int fd; +}; + +struct FDLIST *lastFdInList=(struct FDLIST *)0; + +#define AUTOMATIC 0 +#define UNKNOWN 0 + +/*************************************************************** + get first group or channel +***************************************************************/ +static GCLINK *firstGroupChannel(SLIST *proot,int *plinkType) +{ + *plinkType = UNKNOWN; + if (proot == NULL ) return NULL; + + if ((GCLINK *)sllFirst(proot)) *plinkType = GROUP; + return (GCLINK *)sllFirst(proot); +} + +/*************************************************************** + get next group or channel +***************************************************************/ +static GCLINK *nextGroupChannel(GCLINK *gclink,int *plinkType) +{ + SNODE *pt; + GCLINK *next=0; + GLINK *glink; + + if (gclink == NULL ) return NULL; + + if (*plinkType == GROUP) { + + glink=(GLINK *)gclink; + + /* get first child group*/ + next = (GCLINK *)sllFirst(&(glink->subGroupList)); + if (next) return next; + + /* get first channel */ + next = (GCLINK *)sllFirst(&(glink->chanList)); + if (next) { + *plinkType = CHANNEL; + return next; + } + + } + + /* get next group or channel at same level*/ + next= 0; + pt = (SNODE *)gclink; + while (pt) { + next = (GCLINK *)sllNext(pt); + if (next) return next; + pt =(SNODE *)((GCLINK *)pt)->parent; + if (pt && *plinkType == GROUP ) { + glink=(GLINK *)pt; + next = (GCLINK *)sllFirst(&(glink->chanList)); + *plinkType = CHANNEL; + if (next) return next; + } + *plinkType = GROUP; + } + if (!next) *plinkType = UNKNOWN; + return next; +} + + +/***************************************************************** + alSetNotConnected + *****************************************************************/ +void alSetNotConnected(struct mainGroup *pmainGroup) +{ + GCLINK *gclink; + struct gcData *gcdata; + struct chanData *cdata; + int type; + + if (!toBeConnectedCount) return; + + if (pmainGroup->heartbeatPV.chid && !alCaIsConnected(pmainGroup->heartbeatPV.chid) ) { + errMsg("Heartbeat PV %s Not Connected\n",pmainGroup->heartbeatPV.name); + } + + if (!pmainGroup) return; + + gclink = firstGroupChannel((SLIST *)pmainGroup,&type); + while (gclink) { + gcdata = gclink->pgcData; + alForcePVSetNotConnected(gcdata->pforcePV,gcdata->name); + if (gcdata->sevrchid && !alCaIsConnected(gcdata->sevrchid) ) { + errMsg("Severity PV %s for %s Not Connected\n", + gcdata->sevrPVName, gcdata->name); + } + if (type == CHANNEL ) { + cdata = ((struct chanData *)gcdata); + if (cdata && cdata->ackPVId && !alCaIsConnected(cdata->ackPVId) ) { + errMsg("Acknowledge PV %s for %s Not Connected\n", + cdata->ackPVName, cdata->name); + } + if (cdata && cdata->chid && !alCaIsConnected(cdata->chid)) { + alNewEvent(NOT_CONNECTED,ERROR_STATE,0,-1,"",(CLINK *)gclink); + } + } + gclink = nextGroupChannel(gclink,&type); + } +} + +/***************************************************************** + alPutGblAckT + *****************************************************************/ +void alPutGblAckT(struct mainGroup *pmainGroup) +{ + GCLINK *gclink; + struct chanData *cdata; + int type; + + if (!pmainGroup) return; + if ( !_transients_flag || !_global_flag ||_passive_flag) return; + + gclink = firstGroupChannel((SLIST*)pmainGroup,&type); + while (gclink) { + if (type == CHANNEL) { + cdata = ((CLINK *)gclink)->pchanData; + if ( alCaIsConnected(cdata->chid)) { + /*NOTE: ackt and defaultMask.AckT have opposite meaning */ + short ackt = (cdata->defaultMask.AckT+1)%2; + alCaPutGblAckT(cdata->chid,&ackt); + } + } + gclink = nextGroupChannel(gclink,&type); + } +} + +/******************************************************** + Callback when there is activity on a CA file descriptor +********************************************************/ +static void alProcessCA(XtPointer cd, int *source, XtInputId *id) +{ + alCaPoll(); +} + +/******************************************************** + Callback to register file descriptors +********************************************************/ +void registerCA(void *dummy, int fd, int opened) +{ + struct FDLIST *cur,*next; + int found; +#ifdef WIN32 + #define alhInputMask XtInputReadWinsock +#else + #define alhInputMask XtInputReadMask +#endif + + /* Branch depending on whether the fd is opened or closed */ + if(opened) { + /* Look for a linked list structure for this fd */ + cur=lastFdInList; + while(cur) { + if(cur->fd == fd) { + errMsg("Tried to add a second callback for file descriptor %d\n",fd); + return; + } + cur=cur->prev; + } + /* Allocate and fill a linked list structure for this fd */ + cur=(struct FDLIST *)calloc(1,sizeof(struct FDLIST)); + if(cur == NULL) { + errMsg("Could not allocate space to keep track of file descriptor %d\n",fd); + return; + } + cur->prev=lastFdInList; + cur->inpid=XtAppAddInput(appContext,fd,(XtPointer)alhInputMask, + alProcessCA,NULL); + cur->fd=fd; + lastFdInList=cur; + } else { + /* Find the linked list structure for this fd */ + found=0; + cur=next=lastFdInList; + while(cur) { + if(cur->fd == fd) { + found=1; + break; + } + next=cur; + cur=cur->prev; + } + /* Remove the callback */ + if(found) { + XtRemoveInput(cur->inpid); + if(cur == lastFdInList) lastFdInList=cur->prev; + else next->prev=cur->prev; + free(cur); + } else { + errMsg("Error removing callback for file descriptor %d\n",fd); + } + } +} + +/******************************************************** + Update all areas +********************************************************/ +void alUpdateAreas() +{ + ALINK *area; + + area = 0; + if (areaList) area = (ALINK *)sllFirst(areaList); + while (area) { + if (area->pmainGroup && area->pmainGroup->p1stgroup){ + alHighestSystemSeverity(area->pmainGroup->p1stgroup); + + if ( area->pmainGroup->modified ){ + if ( area->mapped && area->managed){ + /*invokeDialogUpdate(area);*/ + invokeSubWindowUpdate(area->treeWindow); + invokeSubWindowUpdate(area->groupWindow); + } + if (area->managed) updateCurrentAlarmWindow(area); + area->pmainGroup->modified = 0; + } + } + area = (ALINK *)sllNext(area); + } +} + +/***************************************************************** + close all the channel links, groups & subwindows + *****************************************************************/ +void alCaCancel(struct mainGroup *pmainGroup) +{ + GCLINK *gclink; + struct gcData *gcdata; + int type; + + if (!pmainGroup) return; + + if (pmainGroup->heartbeatPV.chid) alCaClearChannel(&(pmainGroup->heartbeatPV.chid)); + + gclink = firstGroupChannel((SLIST *)pmainGroup,&type); + while (gclink) { + gcdata = gclink->pgcData; + alForcePVClearCA(gcdata->pforcePV); + alCaClearChannel(&gcdata->sevrchid); + if (type == CHANNEL) { + alCaClearEvent(&((struct chanData *)gcdata)->evid); + alCaClearChannel(&((struct chanData *)gcdata)->chid); + alCaClearChannel(&((struct chanData *)gcdata)->ackPVId); + if(_description_field_flag) + alCaClearChannel(&((struct chanData *)gcdata)->descriptionId); + } + gclink = nextGroupChannel(gclink,&type); + } + alCaPoll(); +} + diff --git a/alConfig.c b/alConfig.c new file mode 100644 index 0000000..3a7caad --- /dev/null +++ b/alConfig.c @@ -0,0 +1,1299 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alConfig.c */ + +/************************DESCRIPTION*********************************** + Routines related to construction of alarm configuration +**********************************************************************/ + +#include +#include +#include +#include +#include + +#include "postfix.h" +#include "sllLib.h" +#include "alLib.h" +#include "alh.h" +#include "ax.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef UP +#define UP 1 +#endif + +#ifndef DOWN +#define DOWN 0 +#endif + +/* ALARM_ANY must not be equal to any valid alarm severity value */ +#ifndef ALARM_ANY +#define ALARM_ANY ALH_ALARM_NSEV +#endif +/* UP_ALARM must not be equal to any valid alarm severity value */ +#ifndef UP_ALARM +#define UP_ALARM ALARM_ANY + 1 +#endif + +extern char * alhAlarmStatusString[]; +extern char * alhAlarmSeverityString[]; + +extern int _global_flag; +extern int _passive_flag; +extern int DEBUG; +extern int _DB_call_flag; +extern int _description_field_flag; +char applicationName[64]; /* Albert1 applicationName = mainGroupName will be send to DB */ +char deviceName[64]=""; /* Albert1 reserved; will be send to DB */ + + +/* alarm severity command list */ +struct sevrCommand { + ELLNODE node; /* double link list node type */ + int direction; /* alarm severity direction */ + int sev; /* alarm severity level*/ + char *instructionString; /* instructionstring text address */ + char *command; /* command text address */ +}; + +/* alarm status command list */ +struct statCommand { + ELLNODE node; /* double link list node type */ + int stat; /* alarm status value*/ + char *alhAlarmStatusString; /* alarmStatusString text address */ + char *command; /* command text address */ +}; + +/* forward declarations */ +static void print_error( char *buf, char *message); +static void GetGroupLine( char *buf, GLINK **pglink, struct mainGroup *pmainGroup); +static void GetIncludeLine( char *buf, GLINK **pglink, +int caConnect, struct mainGroup *pmainGroup); +static void GetChannelLine( char *buf, GLINK **pglink, CLINK **pclink, +int caConnect, struct mainGroup *pmainGroup); +static void GetOptionalLine( FILE *fp, char *buf, +GCLINK *gclink, int context, int caConnect, struct mainGroup *pmainGroup); +static void alWriteGroupConfig(FILE *fp,SLIST *pgroup); + +static void alConfigTreePrint( FILE *fw, GLINK *glink, char *treeSym); + +/***************************************************** + utility routine +*******************************************************/ +static void print_error(char *buf,char *message) +{ + errMsg("Input error: %s: %s\n",message,buf); +} + +/******************************************************************* + get alarm configuration +*******************************************************************/ +void alGetConfig(struct mainGroup *pmainGroup,char *filename, +int caConnect) +{ + FILE *fp; + char buf[MAX_STRING_LENGTH]; + CLINK *clink; + GLINK *glink; + GCLINK *gclink=0; + int first_char; + int context=0; + + if (filename[0] == '\0') return; + + fp = fopen(filename,"r"); + if(fp==NULL) { + perror("Could not open Alarm Configuration File"); + exit(-1); + } + + glink = pmainGroup->p1stgroup; + clink = NULL; + while( fgets(buf,MAX_STRING_LENGTH,fp) != NULL) { + + /* find first non blank character */ + + first_char = 0; + while( buf[first_char] == ' ' || buf[first_char] == '\t' + || buf[first_char] == '\n') first_char++; + + if (strncmp(&buf[first_char],"GROUP",5)==0) { + GetGroupLine(&buf[first_char],&glink,pmainGroup); + context = GROUP; + gclink = (GCLINK *)glink; + } + else if (strncmp(&buf[first_char],"CHANNEL",7)==0) { + GetChannelLine(&buf[first_char],&glink,&clink,caConnect,pmainGroup); + context = CHANNEL; + gclink = (GCLINK *)clink; + } + else if (strncmp(&buf[first_char],"$",1)==0) { + GetOptionalLine(fp,&buf[first_char],gclink,context,caConnect,pmainGroup); + } + else if (strncmp(&buf[first_char],"INCLUDE",7)==0) { + GetIncludeLine(&buf[first_char],&glink,caConnect,pmainGroup); + context = GROUP; + gclink = (GCLINK *)glink; + } + else if(buf[first_char]=='\0') { + } + else if(buf[first_char]=='#') { + } + else { + print_error(buf,"Invalid input line"); + } + } + + fclose(fp); + return; + +} + +/******************************************************************* + read the Group Line from configuration file +*******************************************************************/ +static void GetGroupLine(char *buf,GLINK **pglink, +struct mainGroup *pmainGroup) +{ + GLINK *glink; + char command[20]; + int rtn; + char parent[PVNAME_SIZE]; + char name[PVNAME_SIZE]; + struct groupData *gdata; + GLINK *parent_link; + + + parent_link = *pglink; + + rtn = sscanf(buf,"%20s%32s%32s",command,parent,name); + + if(rtn!=3) { + print_error(buf,"Invalid GROUP command"); + return; + } + + glink = alCreateGroup(); + glink->pmainGroup = pmainGroup; + gdata = glink->pgroupData; + if (gdata->name) free(gdata->name); + gdata->name = (char *)calloc(1,strlen(name)+1); + strcpy(gdata->name,name); + if (_DB_call_flag) if(strlen(applicationName)==0) strncpy(applicationName,name,64); + + /*parent is NULL , i. e. main group*/ + if(strcmp("NULL",parent)==0) { + + /* commented out following lines to allow INCLUDE to work*/ + /* + if(pmainGroup->p1stgroup!=NULL) { + print_error(buf,"Missing parent"); + return; + } + */ + + if(pmainGroup->p1stgroup==NULL) { + pmainGroup->p1stgroup = glink; + glink->parent = NULL; + *pglink = glink; + return; + } else { + glink->parent = parent_link; + alAddGroup(parent_link,glink); + *pglink = glink; + return; + } + } + + /* must find parent */ + + while(parent_link!=NULL && strcmp(parent_link->pgroupData->name,parent)!=0) + parent_link = parent_link->parent; + + if(parent_link==NULL) { + print_error(buf,"Can not find parent"); + return; + } + + glink->parent = parent_link; + alAddGroup(parent_link,glink); + *pglink = glink; + +} + +/******************************************************************* + read the Include Line from configuration file +*******************************************************************/ +static void GetIncludeLine(char *buf,GLINK **pglink,int caConnect, +struct mainGroup *pmainGroup) +{ + GLINK *glinkHold; + char command[20]; + int rtn; + char parent[PVNAME_SIZE]; + char name[NAMEDEFAULT_SIZE]; + GLINK *parent_link=0; + char filename[NAMEDEFAULT_SIZE]; + + + if (pglink) parent_link = *pglink; + + rtn = sscanf(buf,"%20s%32s%s",command,parent,name); + + if(rtn!=3) { + print_error(buf,"Invalid INCLUDE command"); + return; + } + + /* use default config file directory */ + filename[0] = '\0'; + if (name[0] != '/' && psetup.configDir) { + sprintf(filename,"%s/",psetup.configDir); + } + + /* set filename */ + if (name[0] != '\0') strcat(filename,name); + + + glinkHold = pmainGroup->p1stgroup; + + if(strcmp("NULL",parent)==0) { + if(pmainGroup->p1stgroup!=NULL) { + print_error(buf,"Missing parent"); + return; + } + parent_link = NULL; + } + + /* must find parent */ + while(parent_link!=NULL && strcmp(parent_link->pgroupData->name,parent)!=0) + parent_link = parent_link->parent; + + + pmainGroup->p1stgroup = parent_link; + + /* read config file */ + alGetConfig(pmainGroup,filename,caConnect); + + if (!pmainGroup->p1stgroup) { + print_error(buf,"Ignoring Invalid INCLUDE file"); + return; + } + pmainGroup->p1stgroup = glinkHold; + + *pglink = parent_link; +} + +/******************************************************************* + read the Channel Line from configuration file +*******************************************************************/ +#define TOKEN_MAXSIZE 127 +static void GetChannelLine(char *buf,GLINK **pglink,CLINK **pclink, +int caConnect,struct mainGroup *pmainGroup) +{ + CLINK *clink; + int rtn; + char name[TOKEN_MAXSIZE+2]; + char *parent; + char *mask; + struct chanData *cdata; + GLINK *parent_link; + int i; + + static char token[5][TOKEN_MAXSIZE+1]; + + for (i = 0; i < 5; i++) *token[i] = 0; + rtn = sscanf + (buf, "%127s %127s %127s %127s %127s", + token[0], token[1], token[2], token[3], token[4]); + + /* CDEV line */ + if (strcmp (token[0], "CDEV") == 0) + { + if (rtn < 4) { + print_error(buf,"Invalid CDEV command"); + return; + } + + parent = token[1]; + /* name is "device attribte" */ + sprintf (name, "%s %s", token[2], token[3]); + mask = token[4]; + } + + /* CHANNEL line */ + else + { + if (rtn<3) { + print_error(buf,"Invalid CHANNEL command"); + return; + } + + parent = token[1]; + strcpy (name, token[2]); + mask = token[3]; + } + + clink = alCreateChannel(); + clink->pmainGroup = pmainGroup; + cdata = clink->pchanData; + strncpy(cdata->name,name,PVNAME_SIZE); + + /* must find parent */ + parent_link = *pglink; + while(parent_link!=NULL && strcmp(parent_link->pgroupData->name,parent)!=0) + parent_link = parent_link->parent; + + if(parent_link==NULL) { + print_error(buf,"Can not find parent"); + return; + } + + alAddChan(parent_link,clink); + clink->parent = parent_link; + *pglink = clink->parent; + *pclink = clink; + + if (mask) { + alSetMask(mask,&(cdata->defaultMask)); + alSetCurChanMask(clink,cdata->defaultMask); + } + + if (cdata->curMask.Cancel==1 || cdata->curMask.Disable==1) { + cdata->curSevr=NO_ALARM; + } else { + cdata->curSevr=ERROR_STATE; + } + cdata->curStat=NO_ALARM; + while(parent_link!=NULL) { + parent_link->pgroupData->curSev[cdata->curSevr] ++; + parent_link->pgroupData->unackSev[NO_ALARM] ++; + parent_link->pgroupData->unackBeepSev[NO_ALARM] ++; + parent_link = parent_link->parent; + } + + if (caConnect && strlen(cdata->name) > (size_t) 1) { + alCaConnectChannel(cdata->name,&cdata->chid,clink); + } + + if (caConnect && cdata->curMask.Cancel == 0) { + alCaAddEvent(cdata->chid,&cdata->evid,clink); + } + if (_description_field_flag) { + if( (cdata->description=malloc(128)) == NULL) { + fatalErrMsg("No memory "); + } + getDescriptionRecord(cdata->name,cdata->description,cdata->descriptionId); + } +} + +/******************************************************************* + read the Optional Line from configuration file +*******************************************************************/ +static void GetOptionalLine(FILE *fp,char *buf,GCLINK *gclink, +int context,int caConnect,struct mainGroup *pmainGroup) +{ + struct gcData *gcdata; + struct chanData *cdata=0; + char command[20]; + char name[PVNAME_SIZE]; + char buf2[MAX_STRING_LENGTH]; + char mask[6]; + char string[10]; + double dbl; + short value = 1; + int valueIn; + float rate =1.0; + float rateIn; + char *str; + int i,len; + int rtn; + + /* config optional lines */ + if (strncmp(&buf[1],"BEEPSEVERITY",12)==0) { /*BEEPSEVERITY*/ + + sscanf(buf,"%20s",command); + len = strlen(command); + while( buf[len] == ' ' || buf[len] == '\t') len++; + for (i=1; iheartbeatPV.name) return; + rtn = sscanf(buf,"%20s%32s%f%d",command,name,&rateIn,&valueIn); + if(rtn>=2) { + if(rtn>=3) rate = rateIn; + if(rtn>=4) value = valueIn; + alHeartbeatPVAdd(pmainGroup,name,rate,value); + if (caConnect && strlen(pmainGroup->heartbeatPV.name)) { + alCaConnectHeartbeatPV(pmainGroup->heartbeatPV.name, + &(pmainGroup->heartbeatPV.chid),pmainGroup); + } + } else { + print_error(buf,"Invalid $HEARTBEATPV Line"); + } + return; + } + + + /* group/channel optional lines */ + + if(gclink==NULL) { + print_error(buf,"Logic error: glink is NULL"); + return; + } + gcdata = gclink->pgcData; + if(gcdata==NULL) { + print_error(buf,"Logic error: gcdata is NULL"); + return; + } + + if (strncmp(&buf[1],"BEEPSEVR",8)==0) { /*BEEPSEVR*/ + + sscanf(buf,"%20s",command); + len = strlen(command); + while( buf[len] == ' ' || buf[len] == '\t') len++; + for (i=1; ibeepSevr = i; + } + } + return; + } + + if (strncmp(&buf[1],"FORCEPV ",8)==0) { /*FORCEPV*/ + + if (gcdata->pforcePV && gcdata->pforcePV->name) return; + if (!gcdata->pforcePV) gcdata->pforcePV=(FORCEPV*)calloc(1,sizeof(FORCEPV)); + dbl=0.0; + rtn = sscanf(buf,"%20s%32s%6s%lf%9s",command,name,mask,&dbl,string); + if(rtn>=3) alSetMask(mask,&(gcdata->pforcePV->forceMask)); + if (rtn >= 4) gcdata->pforcePV->forceValue = dbl; + else gcdata->pforcePV->forceValue=1; + if (rtn == 5) { + if (strncmp(string,"NE",2)==0 || strncmp(string,"ne",2)==0) { + gcdata->pforcePV->resetValue = gcdata->pforcePV->forceValue; + } else { + dbl=0.0; + if (sscanf(string,"%lf",&dbl) >= 1) gcdata->pforcePV->resetValue = dbl; + else gcdata->pforcePV->resetValue = 0; + } + } else { + gcdata->pforcePV->resetValue = 0; + } + if(rtn>=2) { + FORCEPVCADATA *puser; + + gcdata->pforcePV->name = (char *)calloc(1,strlen(name)+1); + strcpy(gcdata->pforcePV->name,name); + if (caConnect && strlen(gcdata->pforcePV->name) + && strcmp(gcdata->pforcePV->name,"CALC") !=0 ) { + gcdata->pforcePV->currentValue = -999; + alCaConnectForcePV(gcdata->pforcePV->name,&gcdata->pforcePV->chid,gcdata->name); + puser=(FORCEPVCADATA *)calloc(1,sizeof(FORCEPVCADATA)); + puser->index=-1; + puser->link=gclink; + puser->linktype=context; + gcdata->pforcePV->puser = puser; + alCaAddForcePVEvent (gcdata->pforcePV->chid,puser,&gcdata->pforcePV->evid); + } + } + return; + } + + if (strncmp(&buf[1],"FORCEPV_CALC ",13)==0) { /*FORCEPV_CALC*/ + FORCEPV_CALC* pcalc; + long status=0; + short err=0; + + if (!gcdata->pforcePV) gcdata->pforcePV=(FORCEPV*)calloc(1,sizeof(FORCEPV)); + if (!gcdata->pforcePV->pcalc) + gcdata->pforcePV->pcalc=(FORCEPV_CALC*)calloc(1,sizeof(FORCEPV_CALC)); + pcalc=gcdata->pforcePV->pcalc; + if (pcalc->expression) free(pcalc->expression); + rtn = sscanf(buf,"%20s%s",command,buf2); + pcalc->expression=(char*)calloc(strlen(buf2)+1,sizeof(char)); + strcpy(pcalc->expression,buf2); + /* convert an algebraic expression to symbolic postfix */ + status=postfix(pcalc->expression,buf2,&err); + pcalc->rpbuf=(char*)calloc(strlen(buf2)+1,sizeof(char)); + strcpy(pcalc->rpbuf,buf2); + if(status || err) { + errMsg("FORCEPV_CALC error converting '%s' to symbolic postfix: status=%ld err=%d\n", + pcalc->expression,status,err); + } + return; + } + + if (strncmp(&buf[1],"FORCEPV_CALC_",13)==0) { /*FORCEPV_CALC_A, FORCEPV_CALC_B, ...*/ + rtn = sscanf(buf,"%20s%s",command,name); + if(rtn>=2) { + FORCEPV_CALC* pcalc; + FORCEPVCADATA *puser; + short index; + double dbl; + const char letter[]={"ABCDEF"}; + + for (index=0;indexNO_OF_CALC_PVS -1 || index<0) return; + + if (!gcdata->pforcePV) + gcdata->pforcePV=(FORCEPV*)calloc(1,sizeof(FORCEPV)); + if (!gcdata->pforcePV->pcalc) + gcdata->pforcePV->pcalc= + (FORCEPV_CALC*)calloc(1,sizeof(FORCEPV_CALC)); + pcalc=gcdata->pforcePV->pcalc; + + if (pcalc->name[index]) return; + pcalc->name[index]=(char*)calloc(strlen(name)+1,sizeof(char)); + strcpy(pcalc->name[index],name); + dbl= atof(name); +/*####### errno needs work #######*/ + if (dbl!=0) { + pcalc->value[index] = dbl; + }else { + pcalc->value[index] = -999; + alCaConnectForcePV(pcalc->name[index],&pcalc->chid[index],gcdata->name); + if (pcalc->puser[index]) free(pcalc->puser[index]); + puser=(FORCEPVCADATA *)calloc(1,sizeof(FORCEPVCADATA)); + puser->index=index; + puser->link=gclink; + puser->linktype=context; + pcalc->puser[index] = puser; + alCaAddForcePVEvent (pcalc->chid[index],puser,&pcalc->evid[index]); + } + + } else { + print_error(buf,"Invalid $FORCEPV_CALC Line"); + } + return; + } + + if (strncmp(&buf[1],"SEVRPV",6)==0) { /*SEVRPV*/ + + if(strcmp(gcdata->sevrPVName,"-") != 0) return; + rtn = sscanf(buf,"%20s%32s",command,name); + if(rtn>=2) { + gcdata->sevrPVName = (char *)calloc(1,strlen(name)+1); + strcpy(gcdata->sevrPVName,name); + if (caConnect && strlen(gcdata->sevrPVName) > (size_t) 1) { + alCaConnectSevrPV(gcdata->sevrPVName,&gcdata->sevrchid,gcdata->name); + } + + } else { + print_error(buf,"Invalid $SEVRPV Line"); + } + + return; + } + + if (strncmp(&buf[1],"COMMAND",7)==0) { /*COMMAND*/ + int len; + + if (gcdata->command) return; + sscanf(buf,"%20s",command); + len = strlen(command); + while( buf[len] == ' ' || buf[len] == '\t') len++; + gcdata->command = (char *)calloc(1,strlen(&buf[len])+1); + strcpy(gcdata->command,&buf[len]); + if(gcdata->command[strlen(gcdata->command)-1] == '\n') + gcdata->command[strlen(gcdata->command)-1] = '\0'; + return; + } + + if (strncmp(&buf[1],"SEVRCOMMAND",11)==0) { /*SEVRCOMMAND*/ + int len; + + sscanf(buf,"%20s",command); + len = strlen(command); + while( buf[len] == ' ' || buf[len] == '\t') len++; + str = (char *)calloc(1,strlen(&buf[len])+1); + strcpy(str,&buf[len]); + if(str[strlen(str)-1] == '\n') str[strlen(str)-1] = '\0'; + addNewSevrCommand(&gcdata->sevrCommandList,str); + return; + } + + if (strncmp(&buf[1],"STATCOMMAND",11)==0) { /*STATCOMMAND*/ + int len; + + if(context!=CHANNEL) { + print_error(buf,"Logic error: STATCOMMAND: Context not a channel"); + return; + } + + sscanf(buf,"%20s",command); + len = strlen(command); + while( buf[len] == ' ' || buf[len] == '\t') len++; + str = (char *)calloc(1,strlen(&buf[len])+1); + strcpy(str,&buf[len]); + if(str[strlen(str)-1] == '\n') str[strlen(str)-1] = '\0'; + cdata=(struct chanData *)gcdata; + addNewStatCommand(&cdata->statCommandList,str); + return; + } + + if (strncmp(&buf[1],"ALIAS",5)==0) { /*ALIAS*/ + int len; + + if (gcdata->alias) return; + sscanf(buf,"%20s",command); + len = strlen(command); + while( buf[len] == ' ' || buf[len] == '\t') len++; + gcdata->alias = (char *)calloc(1,strlen(&buf[len])+1); + strcpy(gcdata->alias,&buf[len]); + if(gcdata->alias[strlen(gcdata->alias)-1] == '\n') + gcdata->alias[strlen(gcdata->alias)-1] = '\0'; + return; + } + + if (strncmp(&buf[1],"ALARMCOUNTFILTER",16)==0) { /*ALARMCOUNTFILTER*/ + int count=1; + int seconds=1; + + if(context!=CHANNEL) { + print_error(buf,"Logic error: ALARMCOUNTFILTER: Context not a channel"); + return; + } + + rtn = sscanf(buf,"%20s%i%i",command,&count,&seconds); + if(rtn>=1) { + cdata=(struct chanData *)gcdata; + if (cdata->countFilter) return; + cdata->countFilter = (COUNTFILTER *)calloc(1,sizeof(COUNTFILTER)); + cdata->countFilter->inputCount=1; + cdata->countFilter->inputSeconds=1; + cdata->countFilter->clink=gclink; + cdata->countFilter->stat=NO_ALARM; + cdata->countFilter->sev=ERROR_STATE; + cdata->countFilter->alarmTimeHistory = 0; + cdata->countFilter->countIndex = 0; + } + if(rtn>=2) cdata->countFilter->inputCount=count; + if(rtn>=3) cdata->countFilter->inputSeconds=seconds; + if (cdata->countFilter->inputCount) cdata->countFilter->alarmTimeHistory = + (time_t *)calloc(2*(cdata->countFilter->inputCount),sizeof(time_t)); + return; + } + + if (strncmp(&buf[1],"GUIDANCE",8)==0) { /*GUIDANCE*/ + int len; + + sscanf(buf,"%20s",command); + len = strlen(command); + while( buf[len] == ' ' || buf[len] == '\t' || buf[len] == '\n') len++; + + if (strlen(&buf[len])) { + if (gclink->guidanceLocation) return; + gclink->guidanceLocation = (char *)calloc(1,strlen(&buf[len])+1); + strcpy(gclink->guidanceLocation,&buf[len]); + if(gclink->guidanceLocation[strlen(gclink->guidanceLocation)-1] == '\n') + gclink->guidanceLocation[strlen(gclink->guidanceLocation)-1] = '\0'; + return; + } else { + struct guideLink *pgl; + + while( fgets(buf,MAX_STRING_LENGTH,fp) != NULL) { + + /*change return to null for x message box*/ + + if(buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; + + /* find the first non blank character */ + i = 0; + while( buf[i] == ' ' || buf[i] == '\t') i++; + + if(buf[i]=='$') { + if(strncmp("$END",&buf[i],4) == 0 || + strncmp("$End",&buf[i],4) == 0) + return; + else { + print_error(buf,"Invalid End"); + return; + } + } + pgl = (struct guideLink *)calloc(1,sizeof(struct guideLink)); + pgl->list=(char *)calloc(1,strlen(buf)+1); + strcpy(pgl->list,buf); + sllAdd(&(gclink->GuideList),(SNODE *)pgl); + } + + } + + return; + } + if (strncmp(&buf[1],"ACKPV",5)==0) { /*ACKPV Albert*/ + int rtn; + rtn = sscanf(&buf[7],"%30s%32s",name,command); + + if(rtn>=2) { + cdata=(struct chanData *)gcdata; + cdata->ackPVName = (char *)calloc(1,strlen(name)+1); + strcpy(cdata->ackPVName,name); + cdata->ackPVValue=(short) atoi(command); + if (caConnect && strlen(cdata->ackPVName) > (size_t) 1) { + alCaConnectAckPV(cdata->ackPVName,&cdata->ackPVId,cdata->name); + } + + } else { + print_error(buf,"Invalid $ACKPV Line"); + } + return; + } + print_error(buf,"Invalid Optional Line"); +} + +/******************************************************************* + write system configuration file +*******************************************************************/ +void alWriteConfig(char *filename,struct mainGroup *pmainGroup) +{ + FILE *fw; + fw = fopen(filename,"w"); + if (!fw) return; + if (psetup.beepSevr > 1) + fprintf(fw,"$BEEPSEVERITY %s\n",alhAlarmSeverityString[psetup.beepSevr]); + /*alWriteGroupConfig(fw,(SLIST *)&(pmainGroup->p1stgroup));*/ + alWriteGroupConfig(fw,(SLIST *)pmainGroup); + fclose(fw); +} + +/******************************************************************* + write system configuration file +*******************************************************************/ +static void alWriteGroupConfig(FILE * fw,SLIST *pgroup) +{ + CLINK *clink; + GLINK *glink,*parent; + struct groupData *gdata; + struct chanData *cdata; + char pvmask[6],curmask[6]; + + SNODE *pt,*cpt,*cl,*gl; + struct guideLink *guidelist; + struct sevrCommand *sevrCommand; + struct statCommand *statCommand; + + pt = sllFirst(pgroup); + while (pt) { + glink = (GLINK *)pt; + gdata = glink->pgroupData; + parent = glink->parent; + + if (parent == NULL) { + fprintf(fw,"GROUP %-28s %-28s\n", + "NULL",gdata->name); + } else { + fprintf(fw,"GROUP %-28s %-28s\n", + parent->pgroupData->name, + gdata->name); + } + + if (gdata->beepSevr > 1) + fprintf(fw,"$BEEPSEVR %s\n",alhAlarmSeverityString[gdata->beepSevr]); + + if(gdata->pforcePV) { + alGetMaskString(gdata->pforcePV->forceMask,pvmask); + fprintf(fw,"$FORCEPV %-28s %6s %g ", + gdata->pforcePV->name, + pvmask, + gdata->pforcePV->forceValue); + if ((float)gdata->pforcePV->resetValue==(float)gdata->pforcePV->forceValue ) + fprintf(fw,"%s","NE\n"); + else fprintf(fw,"%g\n",gdata->pforcePV->resetValue); + if (strcmp(gdata->pforcePV->name,"CALC")==0 && gdata->pforcePV->pcalc) { + int i; + const char *letter[]={"A","B","C","D","E","F"}; + + fprintf(fw,"$FORCEPV_CALC %s\n",gdata->pforcePV->pcalc->expression); + for (i=0;ipforcePV->pcalc->name[i]) + fprintf(fw,"$FORCEPV_CALC_%s %s\n",letter[i], + gdata->pforcePV->pcalc->name[i]); + + } + } + } + + if(strcmp(gdata->sevrPVName,"-") != 0) + fprintf(fw,"$SEVRPV %-28s\n", + gdata->sevrPVName); + + if (gdata->command!=NULL) + fprintf(fw,"$COMMAND %s\n",gdata->command); + + if (gdata->alias != NULL) + fprintf(fw,"$ALIAS %s\n",gdata->alias); + + sevrCommand=(struct sevrCommand *)ellFirst(&gdata->sevrCommandList); + while (sevrCommand) { + fprintf(fw,"$SEVRCOMMAND %s\n",sevrCommand->instructionString); + sevrCommand=(struct sevrCommand *)ellNext((ELLNODE *)sevrCommand); + } + + if (glink->guidanceLocation!=NULL) + fprintf(fw,"$GUIDANCE %s\n",glink->guidanceLocation); + + gl = sllFirst(&(glink->GuideList)); + if (gl) fprintf(fw,"$GUIDANCE\n"); + while (gl) { + guidelist = (struct guideLink *)gl; + fprintf(fw,"%s\n",guidelist->list); + gl = sllNext(gl); + if (gl == NULL) fprintf(fw,"$END\n"); + } + + cpt = sllFirst(&(glink->chanList)); + while (cpt) { + clink = (CLINK *)cpt; + + cdata = clink->pchanData; + + alGetMaskString(cdata->curMask,curmask); + + if (strcmp(curmask,"-----") != 0) + fprintf(fw,"CHANNEL %-28s %-28s %6s\n", + glink->pgroupData->name, + cdata->name, + curmask); + else + fprintf(fw,"CHANNEL %-28s %-28s\n", + glink->pgroupData->name, + cdata->name); + + if (cdata->beepSevr > 1) + fprintf(fw,"$BEEPSEVR %s\n",alhAlarmSeverityString[cdata->beepSevr]); + + if(cdata->pforcePV) { + alGetMaskString(cdata->pforcePV->forceMask,pvmask); + fprintf(fw,"$FORCEPV %-28s %6s %g ", + cdata->pforcePV->name, + pvmask, + cdata->pforcePV->forceValue); + if ((float)cdata->pforcePV->resetValue==(float)cdata->pforcePV->forceValue ) + fprintf(fw,"%s","NE\n"); + else fprintf(fw,"%g\n",cdata->pforcePV->resetValue); + if (strcmp(cdata->pforcePV->name,"CALC")==0 && cdata->pforcePV->pcalc) { + int i; + const char *letter[]={"A","B","C","D","E","F"}; + + fprintf(fw,"$FORCEPV_CALC %s\n",cdata->pforcePV->pcalc->expression); + for (i=0;ipforcePV->pcalc->name[i]) + fprintf(fw,"$FORCEPV_CALC_%s %s\n",letter[i], + cdata->pforcePV->pcalc->name[i]); + } + } + } + + if(strcmp(cdata->sevrPVName,"-") != 0) + fprintf(fw,"$SEVRPV %-28s\n",cdata->sevrPVName); + + if (cdata->command != NULL) + fprintf(fw,"$COMMAND %s\n",cdata->command); + + if (cdata->alias != NULL) + fprintf(fw,"$ALIAS %s\n",cdata->alias); + + if (cdata->countFilter != NULL) + fprintf(fw,"$ALARMCOUNTFILTER %i %i\n",cdata->countFilter->inputCount,\ + + cdata->countFilter->inputSeconds); + + sevrCommand=(struct sevrCommand *)ellFirst(&cdata->sevrCommandList); + while (sevrCommand) { + fprintf(fw,"$SEVRCOMMAND %s\n",sevrCommand->instructionString); + sevrCommand=(struct sevrCommand *)ellNext((ELLNODE *)sevrCommand); + } + + statCommand=(struct statCommand *)ellFirst(&cdata->statCommandList); + while (statCommand) { + fprintf(fw,"$STATCOMMAND %s\n",statCommand->alhAlarmStatusString); + statCommand=(struct statCommand *)ellNext((ELLNODE *)statCommand); + } + cpt = sllNext(cpt); + + if (clink->guidanceLocation != NULL) + fprintf(fw,"$GUIDANCE %s\n",clink->guidanceLocation); + + cl = sllFirst(&(clink->GuideList)); + if (cl) fprintf(fw,"$GUIDANCE\n"); + while (cl) { + guidelist = (struct guideLink *)cl; + fprintf(fw,"%s\n",guidelist->list); + cl = sllNext(cl); + if (cl == NULL) fprintf(fw,"$END\n"); + } + + + + } + alWriteGroupConfig(fw,&(glink->subGroupList)); + pt = sllNext(pt); + } + +} + +/******************************************************************* + create a config with a single unnamed main Group +*******************************************************************/ +void alCreateConfig(struct mainGroup *pmainGroup) +{ + GLINK *glink; + + glink = alCreateGroup(); + + pmainGroup->p1stgroup = glink; + + return; +} + +/*************************************************** + treePrint +****************************************************/ +static void alConfigTreePrint(FILE *fw,GLINK *glink,char *treeSym) +{ + CLINK *clink; + struct groupData *gdata; + struct chanData *cdata; + SNODE *pt; + int length; + + int symSize = 3; + static char symMiddle[]="+--"; + static char symContinue[]="| "; + static char symEnd[]="+--"; + static char symBlank[]=" "; + static char symNull[]="\0\0\0"; + + if (glink == NULL) return; + gdata = glink->pgroupData; + + length = strlen(treeSym); + if (length >= MAX_TREE_DEPTH) return; + + + /* find next view sibling */ + pt = sllNext(glink); + + if (length){ + if (pt) strncpy(&treeSym[length-symSize],symMiddle,symSize); + else strncpy(&treeSym[length-symSize],symEnd,symSize); + strncpy(&treeSym[length],symNull,symSize); + } + + fprintf(fw,"%s%-28s\n", + treeSym, + gdata->name); + + if (length){ + if (pt) strncpy(&treeSym[length-symSize],symContinue,symSize); + else strncpy(&treeSym[length-symSize],symBlank,symSize); + } + + pt = sllFirst(&(glink->subGroupList)); + if (pt) strncpy(&treeSym[length],symContinue,symSize); + else strncpy(&treeSym[length],symBlank,symSize); + + pt = sllFirst(&(glink->chanList)); + while (pt){ + + clink = (CLINK *)pt; + cdata = clink->pchanData; + + fprintf(fw,"%s %-28s\n", + treeSym, + cdata->name); + + pt = sllNext(pt); + } + + strncpy(&treeSym[length],symBlank,symSize); + + pt = sllFirst(&(glink->subGroupList)); + while (pt){ + alConfigTreePrint(fw, (GLINK *)pt, treeSym); + pt = sllNext(pt); + } + + strncpy(&treeSym[length],symNull,symSize); + return; +} + +/******************************************************************* + print config tree structure + *******************************************************************/ +void alPrintConfig(FILE *fw,struct mainGroup *pmainGroup) +{ + GLINK *glinkTop; + char treeSym[MAX_TREE_DEPTH+1]; + + memset(treeSym,'\0',MAX_TREE_DEPTH); + glinkTop = (GLINK *)sllFirst(pmainGroup); + + alConfigTreePrint(fw,glinkTop,treeSym); +} + +/******************************************************************* + addNewSevrCommand +*******************************************************************/ +void addNewSevrCommand(ELLLIST *pList,char *str) +{ + struct sevrCommand *sevrCommand; + int len=0; + int i=0; + + sevrCommand = (struct sevrCommand *)calloc(1, sizeof(struct sevrCommand)); + sevrCommand->instructionString = str; + while( str[len] != ' ' && str[len] != '\t' && str[len] != '\0') len++; + while( str[len] == ' ' || str[len] == '\t') len++; + sevrCommand->command = &str[len]; + if(str[0]=='D') { + sevrCommand->direction = DOWN; + len = 5; + } else { + sevrCommand->direction = UP; + len = 3; + } + for (i=0; isev = UP_ALARM; + else sevrCommand->sev = i; + ellAdd(pList,(void *)sevrCommand); + +} + +/******************************************************************* + removeSevrCommandList +*******************************************************************/ +void removeSevrCommandList(ELLLIST *pList) +{ + struct sevrCommand *sevrCommand; + ELLNODE *pt; + + pt=ellFirst(pList); + while (pt) { + sevrCommand=(struct sevrCommand *)pt; + ellDelete(pList,pt); + pt=ellNext(pt); + free(sevrCommand->instructionString); + free(sevrCommand); + } +} + +/******************************************************************* + copySevrCommandList +*******************************************************************/ +void copySevrCommandList(ELLLIST *pListOld,ELLLIST *pListNew) +{ + struct sevrCommand *ptOld, *ptNew; + + ptOld=(struct sevrCommand *)ellFirst(pListOld); + while (ptOld) { + ptNew = (struct sevrCommand *)calloc(1, sizeof(struct sevrCommand)); + ptNew->instructionString = (char *)calloc(1,strlen(ptOld->instructionString)+1); + strcpy(ptNew->instructionString,ptOld->instructionString); + ptNew->command = ptNew->instructionString + (ptOld->command - ptOld->instructionString); + ptNew->direction = ptOld->direction; + ptNew->sev = ptOld->sev; + ellAdd(pListNew,(void *)ptNew); + ptOld=(struct sevrCommand *)ellNext((ELLNODE *)ptOld); + } +} + +/******************************************************************* + spawnSevrCommandList +*******************************************************************/ +void spawnSevrCommandList(ELLLIST *pList,int sev,int sevr_prev) +{ + struct sevrCommand *sevrCommand; + int direction; + + sevrCommand=(struct sevrCommand *)ellFirst(pList); + if (sevrCommand) { + if ( sev > sevr_prev ) direction=UP; + else direction=DOWN; + while (sevrCommand) { + if (sevrCommand->direction==direction) { + if (sevrCommand->sev==ALARM_ANY || sevrCommand->sev==sev ) + processSpawn_callback(NULL,sevrCommand->command,NULL); + else if (direction==UP && sevrCommand->sev==UP_ALARM && + sevr_prev==0) + processSpawn_callback(NULL,sevrCommand->command,NULL); + } + sevrCommand=(struct sevrCommand *)ellNext((ELLNODE *)sevrCommand); + } + } +} + +/******************************************************************* + getStringSevrCommandList +*******************************************************************/ +void getStringSevrCommandList(ELLLIST *pList,char **pstr) +{ + char *str; + struct sevrCommand *sevrCommand; + ELLNODE *pt; + int i; + + pt = ellFirst(pList); + i=0; + while (pt) { + sevrCommand = (struct sevrCommand *)pt; + i += strlen(sevrCommand->instructionString); + i += 1; + pt = ellNext(pt); + } + str = (char*)calloc(1,i+1); + pt = ellFirst(pList); + i=0; + while (pt) { + sevrCommand = (struct sevrCommand *)pt; + strcat(str,sevrCommand->instructionString); + pt = ellNext(pt); + if (pt) strcat(str,"\n"); + i++; + } + *pstr = str; +} + +/******************************************************************* + addNewStatCommand +*******************************************************************/ +void addNewStatCommand(ELLLIST *pList,char *str) +{ + struct statCommand *statCommand; + int len=0; + int i=0; + + statCommand = (struct statCommand *)calloc(1, sizeof(struct statCommand)); + statCommand->alhAlarmStatusString = str; + while( str[len] != ' ' && str[len] != '\t' && str[len] != '\0') len++; + while( str[len] == ' ' || str[len] == '\t') len++; + statCommand->command = &str[len]; + for (i=0; istat = i; + ellAdd(pList,(void *)statCommand); + +} + +/******************************************************************* + removeStatCommandList +*******************************************************************/ +void removeStatCommandList(ELLLIST *pList) +{ + struct statCommand *statCommand; + ELLNODE *pt; + + pt=ellFirst(pList); + while (pt) { + statCommand=(struct statCommand *)pt; + ellDelete(pList,pt); + pt=ellNext(pt); + free(statCommand->alhAlarmStatusString); + /* ????????? + free(statCommand->command); + */ + free(statCommand); + } +} + +/******************************************************************* + copyStatCommandList +*******************************************************************/ +void copyStatCommandList(ELLLIST *pListOld,ELLLIST *pListNew) +{ + struct statCommand *ptOld, *ptNew; + + ptOld=(struct statCommand *)ellFirst(pListOld); + while (ptOld) { + ptNew = (struct statCommand *)calloc(1, sizeof(struct statCommand)); + ptNew->alhAlarmStatusString = (char *)calloc(1,strlen(ptOld->alhAlarmStatusString)+1); + strcpy(ptNew->alhAlarmStatusString,ptOld->alhAlarmStatusString); + ptNew->command = ptNew->alhAlarmStatusString + (ptOld->command - ptOld->alhAlarmStatusString); + ptNew->stat = ptOld->stat; + ellAdd(pListNew,(void *)ptNew); + ptOld=(struct statCommand *)ellNext((ELLNODE *)ptOld); + } +} + +/******************************************************************* + spawnStatCommandList +*******************************************************************/ +void spawnStatCommandList(ELLLIST *pList,int stat,int stat_prev) +{ + struct statCommand *statCommand; + + statCommand=(struct statCommand *)ellFirst(pList); + if ( statCommand && stat != stat_prev) { + while (statCommand) { + if (statCommand->stat == stat ) + processSpawn_callback(NULL,statCommand->command,NULL); + statCommand=(struct statCommand *)ellNext((ELLNODE *)statCommand); + } + } +} + +/******************************************************************* + getStringStatCommandList +*******************************************************************/ +void getStringStatCommandList(ELLLIST *pList,char **pstr) +{ + char *str; + struct statCommand *statCommand; + ELLNODE *pt; + int i; + + pt = ellFirst(pList); + i=0; + while (pt) { + statCommand = (struct statCommand *)pt; + i += strlen(statCommand->alhAlarmStatusString); + i += 1; + pt = ellNext(pt); + } + str = (char*)calloc(1,i+1); + pt = ellFirst(pList); + i=0; + while (pt) { + statCommand = (struct statCommand *)pt; + strcat(str,statCommand->alhAlarmStatusString); + pt = ellNext(pt); + if (pt) strcat(str,"\n"); + i++; + } + *pstr = str; +} + + + diff --git a/alFilter.c b/alFilter.c new file mode 100644 index 0000000..08e6ad1 --- /dev/null +++ b/alFilter.c @@ -0,0 +1,48 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alFilter.c */ + +/************************DESCRIPTION*********************************** + Routines to filter alarm groups and channels +**********************************************************************/ + +#include "alLib.h" + +/*************************************************** + alFilterAll +****************************************************/ +int alFilterAll(GCLINK *gclink) +{ + return(TRUE); +} + +/*************************************************** + alFilterAlarmsOnly +****************************************************/ +int alFilterAlarmsOnly(GCLINK *gclink) +{ + if ( gclink->pgcData->curSevr || gclink->pgcData->unackSevr ) return(TRUE); + return(FALSE); +} + +/*************************************************** + alFilterUnackAlarmsOnly +****************************************************/ +int alFilterUnackAlarmsOnly(GCLINK *gclink) +{ + if ( gclink->pgcData->unackSevr ) return(TRUE); + return(FALSE); +} + diff --git a/alLib.c b/alLib.c new file mode 100644 index 0000000..20c7ca4 --- /dev/null +++ b/alLib.c @@ -0,0 +1,1761 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alLib.c */ + +/************************DESCRIPTION*********************************** + Routines for primative group & channel operation +**********************************************************************/ + +#define DEBUG_CALLBACKS 0 + +#include +#include +#include + +#include "sllLib.h" +#include "alLib.h" +#include "ax.h" + +extern char * alhAlarmSeverityString[]; +extern char * alhAlarmStatusString[]; +extern const char *ackTransientsString[]; + +/* global variables */ +extern int _passive_flag; +extern int _global_flag; +extern int _DB_call_flag; +extern int DEBUG; +extern struct setup psetup; + +/* forward declarations */ +static void alarmCountFilter_callback(XtPointer cd, XtIntervalId *id); +static void alNewAlarmFilter(int stat,int sevr,int acks,int ackt, + char *value,CLINK *clink); +static void alNewAlarmProcess(int stat,int sev, int acks,int ackt, + char *value, CLINK *clink,time_t timeofday); +void alSetAckTChan(CLINK *clink,int ackt); +short alHighestBeepSeverity(int sevr[ALH_ALARM_NSEV], int beepSevr); +static void alSetBeepSevCount(GLINK* glink,int beepSevr,int oldBeepSevr); + +char *Strncat( + char *dest, + const char *src, + int max ) { + + /* max must be >= 0 and no more than stringsize - 1 */ + /* for char string[10]; max must be <= 9 */ + +int l, newMax; +char *s; + + l = strlen( dest ); + newMax = max - l; + if ( newMax < 0 ) { + dest[max] = 0; + return dest; + } + + s = strncat( dest, src, newMax ); + dest[max] = 0; + + return s; + +} + +/********************************************************************** + allocate main Group +***********************************************************************/ +struct mainGroup *alAllocMainGroup() +{ + struct mainGroup *pmainGroup; + + pmainGroup = (struct mainGroup *)calloc(1,sizeof(struct mainGroup)); + pmainGroup->p1stgroup = NULL; + pmainGroup->modified = FALSE; + return(pmainGroup); +} + +/********************************************************************** + append glink at the end of subgrouplist +***********************************************************************/ +void alAddGroup(GLINK *parent,GLINK *glink) +{ + sllAdd(&(parent->subGroupList),(SNODE *)glink); + glink->parent = parent; +} + +/************************************************************************ + append at the end of Channel list +*************************************************************************/ +void alAddChan(GLINK *parent,CLINK *clink) +{ + sllAdd(&(parent->chanList),(SNODE *)clink); + clink->parent = parent; +} + +/********************************************************************** + insert a glink before another glink in the subgrouplist +***********************************************************************/ +void alPrecedeGroup(GLINK *parent,GLINK *sibling,GLINK *glink) +{ + if (parent == NULL || glink == NULL ) return; + sllPrecede(&(parent->subGroupList),(SNODE *)sibling,(SNODE *)glink); + glink->parent = parent; +} + +/********************************************************************** + insert a chan before another chan in the subgrouplist +***********************************************************************/ +void alPrecedeChan(GLINK *parent,CLINK *sibling,CLINK *clink) +{ + + if (parent == NULL || clink == NULL ) return; + sllPrecede(&(parent->chanList),(SNODE *)sibling,(SNODE *)clink); + clink->parent = parent; +} + +/************************************************************************ + delete a channel link from chanList +***********************************************************************/ +void alDeleteChan(CLINK *clink) +{ + struct chanData *cdata; + + if (clink != NULL) { + cdata = clink->pchanData; + if(clink->parent) sllRemove(&(clink->parent->chanList),(SNODE *)clink); + + if (cdata->name) free(cdata->name); + if (cdata->pforcePV) alForcePVDelete(&cdata->pforcePV); + if (strcmp(cdata->sevrPVName,"-") != 0) free(cdata->sevrPVName); + if (cdata->command) free(cdata->command); + if (cdata->countFilter){ + if (cdata->countFilter->alarmTimeHistory){ + free(cdata->countFilter->alarmTimeHistory); + } + if (cdata->countFilter->timeoutId){ + XtRemoveTimeOut(cdata->countFilter->timeoutId); + } + free(cdata->countFilter); + } + if (cdata->noAckTimerId){ + XtRemoveTimeOut(cdata->noAckTimerId); + } + if (cdata->alias) free(cdata->alias); + + removeSevrCommandList(&cdata->sevrCommandList); + removeStatCommandList(&cdata->statCommandList); + + if (clink->guidanceLocation) free(clink->guidanceLocation); + guidanceDeleteGuideList(&clink->GuideList); + + free(cdata); + free(clink); + } +} + +/******************************************************************* + assume that glink had been removed by calling + alRemoveGroup(glink) + before calling this function to free pointers +********************************************************************/ +void alDeleteGroup(GLINK *glink) +{ + SNODE *cnode,*gnode,*next; + GLINK *pt; + struct groupData *gdata; + + if (glink) { + /* free all channels */ + cnode = sllFirst(&(glink->chanList)); + while (cnode) { + next = cnode->next; + alDeleteChan((CLINK *)cnode); + cnode = next; + } + /* free all subgroups */ + gnode = sllFirst(&(glink->subGroupList)); + while (gnode) { + next = gnode->next; + pt = (GLINK *)gnode; + if (pt) { + if (pt->parent) sllRemove(&(pt->parent->subGroupList),(SNODE *)pt); + alDeleteGroup(pt); + gnode = next; + } + } + gdata = glink->pgroupData; + if (gdata->name) free(gdata->name); + if (gdata->pforcePV) alForcePVDelete(&gdata->pforcePV); + if (strcmp(gdata->sevrPVName,"-") != 0) free(gdata->sevrPVName); + if (gdata->command) free(gdata->command); + if (gdata->noAckTimerId){ + XtRemoveTimeOut(gdata->noAckTimerId); + } + if (gdata->alias) free(gdata->alias); + if (gdata->treeSym) free(gdata->treeSym); + + removeSevrCommandList(&gdata->sevrCommandList); + + if (glink->guidanceLocation) free(glink->guidanceLocation); + guidanceDeleteGuideList(&glink->GuideList); + + free(gdata); + free(glink); + } +} + +/*************************************************************** + remove glink from subGroupList +***************************************************************/ +void alRemoveGroup(GLINK *glink) +{ + if (glink) { + if (glink->parent) sllRemove(&(glink->parent->subGroupList),(SNODE *)glink); + /* + glink->node.next = NULL; + glink->parent = NULL; + */ + } +} + +/*************************************************************** + remove clink from chanList +***************************************************************/ +void alRemoveChan(CLINK *clink) +{ + if (clink != NULL) { + if (clink->parent ) sllRemove(&(clink->parent->chanList),(SNODE *)clink); + /* + clink->node.next = NULL; + clink->parent = NULL; + */ + } +} + +/******************************************************************* + set pmainGroup +*******************************************************************/ +void alSetPmainGroup(GLINK *glink,struct mainGroup *pmainGroup) +{ + CLINK *clink; + SNODE *node; + + if (!glink) return; + + glink->pmainGroup = pmainGroup; + + /* update all channels */ + node = sllFirst(&(glink->chanList)); + while (node) { + clink = (CLINK *)node; + clink->pmainGroup = pmainGroup; + node = sllNext(node); + } + + /* update all subGroups */ + node = sllFirst(&(glink->subGroupList)); + while (node) { + alSetPmainGroup((GLINK *)node, pmainGroup); + node = sllNext(node); + } + +} + +/******************************************************************* + make a copy of a Group +*******************************************************************/ +GLINK *alCopyGroup(GLINK *glink) +{ + CLINK *clink; + GLINK *glinkNew; + GLINK *glinkTemp; + struct groupData *gdata; + struct groupData *gdataNew; + char *buff; + SNODE *node; + +#if 0 + +modify parents: + ( int) glink->mask[ALARM_NMASK]; +modify parents: + ( int) glink->viewCount; + +modify children: + (struct mainGroup *) glink->pmainGroup; +modify children: + (void *) glink->pgroupData->treeSym; + +#endif + + if (!glink) return 0; + + glinkNew = alCreateGroup(); + gdataNew = glinkNew->pgroupData; + gdata = glink->pgroupData; + + /* copy viewCount and pmainGroup */ + glinkNew->viewCount = glink->viewCount; + glinkNew->pmainGroup = glink->pmainGroup; + + /* copy command */ + buff = gdata->command; + if (buff){ + gdataNew->command = (char*)calloc(1,strlen(buff)+1); + strcpy(gdataNew->command,buff); + } + + /* copy alias */ + buff = gdata->alias; + if (buff){ + gdataNew->alias = (char*)calloc(1,strlen(buff)+1); + strcpy(gdataNew->alias,buff); + } + + /* copy sevr commands */ + copySevrCommandList(&gdata->sevrCommandList,&gdataNew->sevrCommandList); + + gdataNew->beepSevr = gdata->beepSevr; + + /* copy sevrPV info */ + buff = gdata->sevrPVName; + if (buff){ + gdataNew->sevrPVName = (char*)calloc(1,strlen(buff)+1); + strcpy(gdataNew->sevrPVName,buff); + } + ; + + + /* copy name */ + if (gdataNew->name) free(gdataNew->name); + buff = gdata->name; + if (buff){ + gdataNew->name = (char*)calloc(1,strlen(buff)+1); + strcpy(gdataNew->name,buff); + } + + /* copy treeSym */ + buff = gdata->treeSym; + if (buff){ + gdataNew->treeSym = (char*)calloc(1,strlen(buff)+1); + strcpy(gdataNew->treeSym,buff); + } + + /* copy forcePV info */ + if (gdata->pforcePV) gdataNew->pforcePV=alForcePVCopy(gdata->pforcePV); + + /* copy guidance */ + buff = glink->guidanceLocation; + if (buff) { + glinkNew->guidanceLocation = (char*)calloc(1,strlen(buff)+1); + strcpy(glinkNew->guidanceLocation,buff); + } + guidanceCopyGuideList(&glinkNew->GuideList,&glink->GuideList); + + /* copy all channels */ + node = sllFirst(&(glink->chanList)); + while (node) { + clink = alCopyChan((CLINK *)node); + ; + alAddChan(glinkNew, clink); + node = sllNext(node); + } + + /* copy all subGroups */ + node = sllFirst(&(glink->subGroupList)); + while (node) { + glinkTemp = alCopyGroup((GLINK *)node); + ; + alAddGroup(glinkNew, glinkTemp); + node = sllNext(node); + } + + return(glinkNew); + +} + +/******************************************************************* + make a copy of a Channel +*******************************************************************/ +CLINK *alCopyChan(CLINK *clink) +{ + CLINK *clinkNew; + char *buff; + struct chanData *cdataNew; + struct chanData *cdata; + int i; + +#if 0 + +modify parents: + ( int) clink->mask[ALARM_NMASK]; +modify parents: + ( int) clink->viewCount; + +modify children: + (struct mainGroup *) clink->pmainGroup; +modify children: + (void *) clink->pchanData->treeSym; + +#endif + + if (!clink) return 0; + + clinkNew = alCreateChannel(); + cdataNew = clinkNew->pchanData; + cdata = clink->pchanData; + + /* copy viewCount and pmainGroup */ + clinkNew->viewCount = clink->viewCount; + clinkNew->pmainGroup = clink->pmainGroup; + + /* copy command */ + buff = cdata->command; + if (buff){ + cdataNew->command = (char*)calloc(1,strlen(buff)+1); + strcpy(cdataNew->command,buff); + } + + /* copy countFilter */ + if (cdata->countFilter){ + cdataNew->countFilter = (COUNTFILTER *)calloc(1,sizeof(COUNTFILTER)); + cdataNew->countFilter->inputCount=cdata->countFilter->inputCount; + cdataNew->countFilter->inputSeconds=cdata->countFilter->inputSeconds; + cdataNew->countFilter->clink=cdata->countFilter->clink; + if (cdataNew->countFilter->inputCount){ + cdataNew->countFilter->alarmTimeHistory = + (time_t *)calloc(2*(cdataNew->countFilter->inputCount),sizeof(time_t)); + for (i=0;i<=2*(cdataNew->countFilter->inputCount)-1;i++){ + cdataNew->countFilter->alarmTimeHistory[i]=cdata->countFilter->alarmTimeHistory[i]; + } + } + } + + /* copy alias */ + buff = cdata->alias; + if (buff){ + cdataNew->alias = (char*)calloc(1,strlen(buff)+1); + strcpy(cdataNew->alias,buff); + } + + /* copy sevr commands */ + copySevrCommandList(&cdata->sevrCommandList,&cdataNew->sevrCommandList); + + /* copy stat commands */ + copyStatCommandList(&cdata->statCommandList,&cdataNew->statCommandList); + + /* copy sevrPV info */ + buff = cdata->sevrPVName; + if (buff){ + cdataNew->sevrPVName = (char*)calloc(1,strlen(buff)+1); + strcpy(cdataNew->sevrPVName,buff); + } + + cdataNew->beepSevr = cdata->beepSevr; + + /* copy name */ + if (cdataNew->name) free(cdataNew->name); + buff = cdata->name; + if (buff){ + cdataNew->name = (char*)calloc(1,strlen(buff)+1); + strcpy(cdataNew->name,buff); + } + + /* copy forcePV info */ + if (cdata->pforcePV) cdataNew->pforcePV=alForcePVCopy(cdata->pforcePV); + + /* copy guidance */ + buff = clink->guidanceLocation; + if (buff) { + clinkNew->guidanceLocation = (char*)calloc(1,strlen(buff)+1); + strcpy(clinkNew->guidanceLocation,buff); + } + guidanceCopyGuideList(&clinkNew->GuideList,&clink->GuideList); + + return(clinkNew); + +} + +/******************************************************************* + Create a new Group +*******************************************************************/ +GLINK *alCreateGroup() +{ + GLINK *link; + struct groupData *gdata; + + link = (GLINK *)calloc(1,sizeof(GLINK)); + link->pgroupData = (struct groupData *)calloc(1,sizeof(struct groupData)); + gdata = link->pgroupData; + + link->viewCount = 1; + gdata->name = (char *)calloc(1,PVNAME_SIZE+1); + strcpy(gdata->name,"Unnamed_Group"); + gdata->sevrPVName = "-"; + + return(link); +} + +/******************************************************************* + Create a new Channel +*******************************************************************/ +CLINK *alCreateChannel() +{ + CLINK *link; + struct chanData *cdata; + + link = (CLINK *)calloc(1,sizeof(CLINK)); + link->pchanData = (struct chanData *)calloc(1,sizeof(struct chanData)); + cdata = link->pchanData; + + link->viewCount =1; + cdata->name = (char *)calloc(1,PVNAME_SIZE+1); + strcpy(cdata->name,"Unnamed_Channel"); + cdata->sevrPVName = "-"; + + alSetMask("-----",&(cdata->curMask)); + cdata->defaultMask = cdata->curMask; + + return(link); +} + +/************************************************************ + this function set Mask from input string +************************************************************/ +void alSetMask(char *s4,MASK *mask) +{ + char *s; + size_t i; + mask->AckT = 0; + mask->Log = 0; + mask->Ack = 0; + mask->Disable = 0; + mask->Cancel = 0; + mask->Unused = 0; + for (i=0;iAckT = 1; + else if (*s == 'L') mask->Log = 1; + else if (*s == 'D') mask->Disable = 1; + else if (*s == 'C') mask->Cancel = 1; + else if (*s == 'A') mask->Ack = 1; + else continue; + } +} + +/*********************************************************** + get mask string for a know MASK mask +*************************************************************/ +void alGetMaskString(MASK mask,char *s) +{ + strcpy(s,"-----"); + if (mask.Cancel == 1) *s = 'C'; + if (mask.Disable == 1) *(s+1) = 'D'; + if (mask.Ack == 1) *(s+2) = 'A'; + if (mask.AckT == 1) *(s+3) = 'T'; + if (mask.Log == 1) *(s+4) = 'L'; + *(s+5) = '\0'; +} + +/****************************************************** + alarmCountFilter_callback +******************************************************/ + +static void alarmCountFilter_callback(XtPointer cd, XtIntervalId *id) +{ + COUNTFILTER *countFilter=(COUNTFILTER *)cd; + time_t alarmTime; + int j; + +#if DEBUG_CALLBACKS + { + static int n=0; + + printf("alarmCountFilter_callback: n=%d\n",n++); + } +#endif + alarmTime = countFilter->alarmTime; + countFilter->alarmTime=0; + countFilter->timeoutId=0; + /* reset alarm count filter when new alarm is processed */ + if (countFilter->inputCount){ + for (j=0;j<=2*(countFilter->inputCount)-1;j++){countFilter->alarmTimeHistory[j]=0;} + } + countFilter->countIndex=0; + alNewAlarmProcess(countFilter->stat,countFilter->sev, + countFilter->acks,countFilter->ackt, + countFilter->value,countFilter->clink,alarmTime); +} + + +/****************************************************** + alSaveAlarmEvent +******************************************************/ + +void alSaveAlarmEvent(int stat,int sevr,int acks,int ackt,char *value,CLINK *clink) +{ + struct chanData *cdata = clink->pchanData; + + cdata->caAlarmEvent.stat = stat; + cdata->caAlarmEvent.sevr = sevr; + cdata->caAlarmEvent.acks = acks; + cdata->caAlarmEvent.ackt = ackt; + strcpy(cdata->caAlarmEvent.value,value); + cdata->caAlarmEvent.clink = clink; +} + +/****************************************************** + alConnectEvent +******************************************************/ + +void alConnectEvent(CLINK *clink) +{ + struct chanData *cdata = clink->pchanData; + + /* skip initial connection */ + if ( clink && !(cdata->curStat==NO_ALARM && cdata->curSevr==ERROR_STATE )) { + alNewEvent(cdata->caAlarmEvent.stat,cdata->caAlarmEvent.sevr, + cdata->caAlarmEvent.acks,cdata->caAlarmEvent.ackt, + cdata->caAlarmEvent.value,clink); + } +} + + +/****************************************************** + alNewEvent +******************************************************/ + +void alNewEvent(int stat,int sevr,int acks,int acktCA,char *value,CLINK *clink) +{ + struct chanData *cdata; + time_t alarmTime; + unsigned ackt; + + if (clink == NULL ) return; + cdata = clink->pchanData; + if (cdata == NULL ) return; + + if (acktCA == -1) ackt = cdata->curMask.AckT; + /* NOTE: ackt and acktCA have opposite meaning */ + else ackt = (acktCA+1)%2; + + if (cdata->countFilter) { + alNewAlarmFilter(stat,sevr,acks,ackt,value,clink); + } else { + /* set time of alarm */ + alarmTime = time(0L); + alNewAlarmProcess(stat,sevr,acks,ackt,value,clink,alarmTime); + } +} + + +/*********************************************************** + alNewAlarmFilter +************************************************************/ +void alNewAlarmFilter(int stat,int sev,int acks,int ackt,char *value,CLINK *clink) +{ + struct chanData *cdata; + int sevr_prev, i, j; + time_t alarmTime; + COUNTFILTER *countFilter; + + if (clink == NULL ) return; + cdata = clink->pchanData; + if (cdata == NULL ) return; + + /* set time of alarm */ + alarmTime = time(0L); + + countFilter = cdata->countFilter; + sevr_prev = countFilter->sev; + countFilter->stat = stat; + countFilter->sev = sev; + countFilter->acks = acks; + countFilter->ackt = ackt; + strcpy(countFilter->value,value); + + /* Process the initial state */ + if (cdata->curStat==NO_ALARM && cdata->curSevr==ERROR_STATE ) { + alNewAlarmProcess(stat,sev,acks,ackt,value,clink,alarmTime); + return; + } + + /* Process if inputCount or inputSeconds is zero */ + if (countFilter->inputSeconds==0 || countFilter->inputCount==0) { + alNewAlarmProcess(stat,sev,acks,ackt,value,clink,alarmTime); + return; + } + + /*remove timeout and call alNewAlarmProcess to update acks and ackt*/ + if (cdata->curSevr==0 && sev==0 ){ + if(acks==0) alNewAlarmProcess(stat,sev,acks,ackt,value,clink,alarmTime); + if (countFilter->timeoutId){ + XtRemoveTimeOut(countFilter->timeoutId); + countFilter->timeoutId=0; + } + } + /* remove timeout and call alNewAlarmProcess */ + if (cdata->curSevr!=0 && sev!=0 ){ + alNewAlarmProcess(stat,sev,acks,ackt,value,clink,alarmTime); + if (countFilter->timeoutId){ + XtRemoveTimeOut(countFilter->timeoutId); + countFilter->timeoutId=0; + } + } + /* if no timeout then add timeout */ + if ( cdata->curSevr==0 && sev!=0 ){ + if (countFilter->timeoutId==0) { + countFilter->timeoutId = XtAppAddTimeOut(appContext, + (unsigned long)countFilter->inputSeconds*1000, + alarmCountFilter_callback,(XtPointer)countFilter); + countFilter->alarmTime=alarmTime; + } + } + + + /* process changes in acks and ackt and if no timeout then add timeout */ + if ( cdata->curSevr!=0 && sev==0 ){ + alNewAlarmProcess(cdata->curStat,cdata->curSevr,acks,ackt,value,clink,alarmTime); + if (countFilter->timeoutId==0) { + countFilter->timeoutId = XtAppAddTimeOut(appContext, + (unsigned long)countFilter->inputSeconds*1000, + alarmCountFilter_callback,(XtPointer)countFilter); + countFilter->alarmTime=alarmTime; + } + } + + /* check in/out alarm count within time interval*/ + if ( (sevr_prev==0 && sev!=0) || (sevr_prev!=0 && sev==0)){ + i = countFilter->countIndex; + if ( !countFilter->alarmTimeHistory || + (countFilter->alarmTimeHistory[i] && + (((int)difftime(alarmTime,countFilter->alarmTimeHistory[i]))<=countFilter->inputSeconds))){ + /* reset alarm count filter when new alarm is processed */ + if (countFilter->inputCount){ + for (j=0;j<=2*(countFilter->inputCount)-1;j++){countFilter->alarmTimeHistory[j]=0;} + } + if (countFilter->timeoutId){ + XtRemoveTimeOut(countFilter->timeoutId); + countFilter->timeoutId=0; + } + countFilter->countIndex=0; + alNewAlarmProcess(stat,sev,acks,ackt,value,clink,alarmTime); + } else { + countFilter->alarmTimeHistory[i] = alarmTime; + countFilter->countIndex++; + if (countFilter->countIndex >= 2*(countFilter->inputCount) ){ + countFilter->countIndex = 0; + } + } + } +} + +/*********************************************************** + alNewAlarmProcess +************************************************************/ +static void alNewAlarmProcess(int stat,int sev,int acks,int ackt,char *value, +CLINK *clink,time_t timeofday) +{ + struct chanData *cdata; + struct groupData *gdata; + GLINK *glink; + MASK mask; + int stat_prev,sevr_prev,sevrHold; + int viewCount=0; + int prevViewCount=0; + + if (clink == NULL ) return; + cdata = clink->pchanData; + if (cdata == NULL ) return; + + /* We save the current alarm values on a disconnect event and issue + a new alarm event on reconnect because ca may not issue a new Alarm + event after reconnect if alarm values not changed */ + if (stat==NOT_CONNECTED && sev==ERROR_STATE) { + alSaveAlarmEvent(cdata->curStat, cdata->curSevr, cdata->unackSevr, + (cdata->curMask.AckT+1)%2, cdata->value, clink); + } + + if (sev >= ALH_ALARM_NSEV) sev = ALH_ALARM_NSEV-1; + if (stat >= ALH_ALARM_NSTATUS) stat = ALH_ALARM_NSTATUS-1; + mask = cdata->curMask; + strncpy(cdata->value,value,MAX_STRING_SIZE-1); + psetup.newUnackBeepSevr=0; + + if (_global_flag) { + if (cdata->unackSevr != acks ) { + if ( cdata->curMask.Disable == 0 && cdata->curMask.Ack == 0 ) { + alSetUnackSevChan(clink,acks); + } else { + cdata->unackSevr = acks; + } + } + if (cdata->curMask.AckT != ackt) { + alSetAckTChan(clink,ackt); + } + if (cdata->curStat == stat && cdata->curSevr == sev && + cdata->curMask.Log == 0) { + + alLogAlarmMessage(&timeofday,REGULAR_RECORD,clink, + "(%s / %s)", + alhAlarmSeverityString[acks], + ackTransientsString[ackt]); + } + } + + if (cdata->curStat == stat && cdata->curSevr == sev) return; + + prevViewCount = awViewViewCount((void *)clink); + + stat_prev = cdata->curStat; + sevr_prev = cdata->curSevr; + + cdata->curStat = stat; + cdata->curSevr = sev; + + viewCount = awViewViewCount((void *)clink); + clink->viewCount = viewCount; + + /* + * log the channel alarm at the alarm logfile + */ + if (mask.Log == 0) { + /* Don't log the initial connection */ + if ( !(stat_prev==NO_ALARM && sevr_prev==ERROR_STATE )) { + + if (_global_flag) alLogAlarmMessage(&timeofday,REGULAR_RECORD,clink, + "(%s / %s)", alhAlarmSeverityString[acks], + ackTransientsString[ackt]); + else alLogAlarmMessage(&timeofday,REGULAR_RECORD,clink, + "( / )"); + + } + } + + /* + * disabled alarm special handling + */ + if (mask.Disable == 1) return; + + /* + * update current alarm history strings + */ + updateCurrentAlarmString(clink->pmainGroup->area, + &timeofday,cdata->name,cdata->value, stat,sev); + + /* + * set modification indicator for channel + */ + clink->modified = 1; + clink->pmainGroup->modified = TRUE; + + /* + * spawn SEVRCOMMAND for the channel + * write the severity value to sevrPV channels + */ + + if ( sev != sevr_prev ) { + spawnSevrCommandList(&cdata->sevrCommandList,sev,sevr_prev); + if (_global_flag && !_passive_flag) { + if (cdata->sevrchid) alCaPutSevrValue(cdata->sevrchid,&cdata->curSevr); + } + } + + /* + * spawn STATCOMMAND for the channel + */ + + if ( stat != stat_prev ) + spawnStatCommandList(&cdata->statCommandList,stat,stat_prev); + + /* + * spawn SEVRCOMMAND for all the parent groups + * update curSev[] of all the parent groups + * write the severity value to sevrPV channels + */ + glink = clink->parent; + while (glink) { + gdata = glink->pgroupData; + gdata->curSev[sevr_prev]--; + gdata->curSev[sev]++; + sevrHold=gdata->curSevr; + gdata->curSevr=alHighestSeverity(gdata->curSev); + + if ( sevrHold != gdata->curSevr ) { + spawnSevrCommandList(&gdata->sevrCommandList, + gdata->curSevr,sevrHold); + if (_global_flag && !_passive_flag) { + if (gdata->sevrchid) alCaPutSevrValue(gdata->sevrchid,&gdata->curSevr); + } + } + + glink->modified = 1; + glink = glink->parent; + } + + /* + * mark subWindows for add of a new line + */ + awViewAddNewAlarm(clink,prevViewCount,viewCount); + + /* + * alarm not required to acknowledge + */ + if (mask.Ack == 1) return; + + /* + * update unackSev[] and unackSevr of all parent groups + * transient alarm not required to acknowledge + */ + if (!_global_flag) { + if (sev >= cdata->unackSevr) { + alSetUnackSevChan(clink,sev); + } else { + if (mask.AckT==1) { + alSetUnackSevChan(clink,sev); + } + } + } + + /* + * reset silenceCurrent state to FALSE + */ + if (psetup.silenceCurrent && (psetup.newUnackBeepSevr>=psetup.beepSevr) ) + silenceCurrentReset(clink->pmainGroup->area); + +} + +/****************************************************************** + highest system severity used for icon +*****************************************************************/ +void alHighestSystemSeverity(GLINK *glink) +{ + psetup.highestSevr = alHighestSeverity(glink->pgroupData->curSev); + psetup.highestUnackSevr = alHighestSeverity(glink->pgroupData->unackSev); + psetup.highestUnackBeepSevr = alHighestBeepSeverity(glink->pgroupData->unackBeepSev,glink->pgroupData->beepSevr); +} + +/****************************************************************** + highest severity +*****************************************************************/ +short alHighestSeverity(int sevr[ALH_ALARM_NSEV]) +{ + short j=0; + for (j=ALH_ALARM_NSEV-1;j>0;j--) { + if (sevr[j] > 0) return(j); + } + return(0); +} + +/****************************************************************** + highest beep severity +*****************************************************************/ +short alHighestBeepSeverity(int sevr[ALH_ALARM_NSEV], int beepSevr) +{ + short j=0; + if (beepSevr == 0) beepSevr=1; + for (j=ALH_ALARM_NSEV-1;j>=beepSevr;j--) { + if (sevr[j] > 0) return(j); + } + return(0); +} + +/************************************************************* + *This function forces the mask in the channel according to the + *maskIndex and opCode a user selected from the mask menus. + ***************************************************************/ +void alForceChanMask(CLINK *clink,int index,int op) +{ + MASK mask; + + mask = clink->pchanData->curMask; + + switch (index) { + case ALARMCANCEL: + if (op == MASK_OFF) mask.Cancel = 0; + else if (op == MASK_ON) mask.Cancel = 1; + else if (op == MASK_RESET) + mask.Cancel = + clink->pchanData->defaultMask.Cancel; + break; + + case ALARMDISABLE: + if (op == MASK_OFF) mask.Disable = 0; + else if (op == MASK_ON) mask.Disable = 1; + else if (op == MASK_RESET) + mask.Disable = + clink->pchanData->defaultMask.Disable; + break; + + case ALARMACK: + if (op == MASK_OFF) mask.Ack = 0; + else if (op == MASK_ON) mask.Ack = 1; + else if (op == MASK_RESET) + mask.Ack = + clink->pchanData->defaultMask.Ack; + break; + + case ALARMACKT: + if (op == MASK_OFF) mask.AckT = 0; + else if (op == MASK_ON) mask.AckT = 1; + else if (op == MASK_RESET) + mask.AckT = + clink->pchanData->defaultMask.AckT; + break; + + case ALARMLOG: + if (op == MASK_OFF) mask.Log = 0; + else if (op == MASK_ON) mask.Log = 1; + else if (op == MASK_RESET) + mask.Log = + clink->pchanData->defaultMask.Log; + break; + + } + + alChangeChanMask(clink,mask); + + if(_DB_call_flag) alLog2DBMask(clink->pchanData->name); + +} + +/************************************************************************* + *This function forces the mask for all channels in the group according to the + *maskIndex and opCode a user selected from the mask menus. + **********************************************************************/ +void alForceGroupMask(GLINK *glink,int index,int op) +{ + GLINK *group; + CLINK *clink; + SNODE *pt; + + /* + * for all channels in this group + */ + pt = sllFirst(&(glink->chanList)); + while (pt) { + clink = (CLINK *)pt; + alForceChanMask(clink,index,op); + pt = sllNext(pt); + } + /* + * for all subgroups + */ + pt = sllFirst(&(glink->subGroupList)); + while (pt) { + group = (GLINK *)pt; + alForceGroupMask(group,index,op); + pt = sllNext(pt); + } +} + +/************************************************************************** + * This function updates the parent group masks. 'index' gives the index of + * group mask. 'op' specifies ON / OFF of new channel mask setting. + **************************************************************************/ +static void alUpdateGroupMask(CLINK *clink,int index,int op) +{ + + char buff[LINEMESSAGE_SIZE], labelStr[80+1]; + MASK mask; + int i, ok; + XmString str; + ALINK *areaTop; + + struct groupData *gdata; + GLINK *parent, *top; + + parent = clink->parent; + top = NULL; + + switch (op) { + + case MASK_OFF: /* turns off */ + while (parent) { + gdata = parent->pgroupData; + if (gdata->mask[index] > 0) gdata->mask[index]--; + else + errMsg("Error:alUpdateGroupMask, mask[%d] < 1\n",index); + parent->modified = 1; + + if ( !(parent->parent) ) { + top = parent; + } + + parent = parent->parent; + } + break; + + case MASK_ON: /* turns on */ + while (parent) { + gdata = parent->pgroupData; + gdata->mask[index]++; + parent->modified = 1; + + if ( !(parent->parent) ) { + top = parent; + } + + parent = parent->parent; + } + break; + + } + + clink->pmainGroup->modified = TRUE; + + if ( top ) { + + ok = 1; + + if ( !top->pgroupData ) { + ok = 0; + } + else if ( !top->pgroupData->mask ) { + ok = 0; + } + + if ( ok ) { + + mask.Unused = mask.Cancel = mask.Disable = mask.Ack = mask.AckT = mask.Log = 0; + for ( i=0; ipgroupData->mask[i] > 0 ); + } + else if ( i == ALARMDISABLE ) { + mask.Disable = ( top->pgroupData->mask[i] > 0 ); + } + else if ( i == ALARMACK ) { + mask.Ack = ( top->pgroupData->mask[i] > 0 ); + } + else if ( i == ALARMACKT ) { + mask.AckT = ( top->pgroupData->mask[i] > 0 ); + } + else if ( i == ALARMLOG ) { + mask.Log = ( top->pgroupData->mask[i] > 0 ); + } + } + + alGetMaskString(mask,buff); + + } + + ok = 1; + + if ( !top->pmainGroup ) { + ok = 0; + } + else if ( !top->pmainGroup->area ) { + ok = 0; + } + + if ( ok ) { + + areaTop = (ALINK *) top->pmainGroup->area; + + strncpy( labelStr, areaTop->blinkString, 80 ); + labelStr[80] = 0; + + if ( strcmp( buff, "-----" ) != 0 ) { + + Strncat( labelStr, " <", 80 ); + labelStr[80] = 0; + + Strncat( labelStr, buff, 80 ); + labelStr[80] = 0; + + Strncat( labelStr, ">", 80 ); + labelStr[80] = 0; + + } + + str = XmStringCreateSimple(labelStr); + XtVaSetValues(areaTop->blinkButton, + XmNlabelString, str, + NULL); + XmStringFree(str); + + } + + } + +} + +/************************************************************************** + * This function checks each bit of the new mask against to the current + * mask. If the bit of mask to be changed then call alUpdateGroupMask + * to update the parent group mask. Finally updates current channel mask. + **************************************************************************/ +void alChangeChanMask(CLINK *clink,MASK mask) +{ + struct chanData *cdata; + struct groupData *gdata; + GLINK *parent; + int change=0,saveSevr; + int sevrHold, unackSevrHold; + short disabledSevr = -1; + + cdata = clink->pchanData; + + /* + * check each bit of new mask with current mask + */ + + if (mask.Cancel != cdata->curMask.Cancel) { + + alUpdateGroupMask(clink,ALARMCANCEL,mask.Cancel); + cdata->curMask.Cancel = mask.Cancel; + change =1; + + if (mask.Cancel == 1 ) { + if (cdata->evid) alCaClearEvent(&cdata->evid); + if (cdata->curMask.Disable == 0) { + if (cdata->unackSevr > NO_ALARM) + alSetUnackSevChan(clink,NO_ALARM); + if (cdata->curSevr > NO_ALARM) { + saveSevr = cdata->curSevr; + cdata->curSevr = NO_ALARM; + cdata->curStat = NO_ALARM; + parent = clink->parent; + while(parent) { + gdata = (struct groupData *)(parent->pgroupData); + gdata->curSev[saveSevr]--; + gdata->curSev[cdata->curSevr]++; + + /* + * spawn SEVRCOMMAND for all the parent groups + * update curSev[] of all the parent groups + */ + sevrHold=gdata->curSevr; + gdata->curSevr=alHighestSeverity(gdata->curSev); + if ( sevrHold != gdata->curSevr ) { + spawnSevrCommandList(&gdata->sevrCommandList, + gdata->curSevr,sevrHold); + } + + parent->modified = 1; + parent = parent->parent; + } + } + } + + } + + if (mask.Cancel == 0 && cdata->evid == NULL) { +/* + if (cdata->curMask.Disable == 0) { + if (cdata->unackSevr == NO_ALARM) + alSetUnackSevChan(clink,ERROR_STATE); + if (cdata->curSevr == NO_ALARM) { + cdata->curSevr = ERROR_STATE; + cdata->curStat = NOT_CONNECTED; + parent = clink->parent; + while(parent) { + gdata = (struct groupData *)(parent->pgroupData); + gdata->curSev[cdata->curSevr]--; + gdata->curSev[ERROR_STATE]++; + parent->modified = 1; + parent = parent->parent; + } + } + } +*/ + if (cdata->curMask.Disable == 0 && cdata->curSevr > 0) { + saveSevr = cdata->curSevr; + cdata->curSevr = NO_ALARM; + alNewAlarmProcess(cdata->curStat,saveSevr,cdata->unackSevr, + cdata->curMask.AckT,cdata->value,clink,time(0L)); + } + alCaAddEvent(cdata->chid,&cdata->evid,clink); + } + + } + + if (mask.Disable != cdata->curMask.Disable) { + alUpdateGroupMask(clink,ALARMDISABLE,mask.Disable); + + cdata->curMask.Disable = mask.Disable; + + change = 1; + if (mask.Disable == 1 && mask.Cancel == 0) { + if (cdata->unackSevr > 0) { + unackSevrHold = cdata->unackSevr; + alSetUnackSevChan(clink,NO_ALARM); + if (_global_flag) cdata->unackSevr = unackSevrHold; + } + + if (cdata->curSevr > 0) { + parent = clink->parent; + while(parent) { + gdata = (struct groupData *)(parent->pgroupData); + gdata->curSev[cdata->curSevr]--; + gdata->curSev[NO_ALARM]++; + /* spawn SEVRCOMMAND for all the parent groups + * update curSev[] of all the parent groups + */ + sevrHold=gdata->curSevr; + gdata->curSevr=alHighestSeverity(gdata->curSev); + if ( sevrHold != gdata->curSevr ) { + spawnSevrCommandList(&gdata->sevrCommandList,gdata->curSevr,sevrHold); + } + parent->modified = 1; + parent = parent->parent; + } + } + if (_global_flag && !_passive_flag && cdata->sevrchid) { + alCaPutSevrValue(cdata->sevrchid,&disabledSevr); + } + + } + + if (mask.Disable == 0 && mask.Cancel == 0) { + if (cdata->curSevr > 0) { + sevrHold = cdata->curSevr; + unackSevrHold = cdata->unackSevr; + cdata->curSevr = NO_ALARM; + cdata->unackSevr = NO_ALARM; + alNewAlarmProcess(cdata->curStat,sevrHold,unackSevrHold, + cdata->curMask.AckT,cdata->value,clink,time(0L)); + } else { + if (cdata->unackSevr > 0 && _global_flag ) { + ackChan(clink); + alLogOpModMessage(0,(GCLINK*)clink,"Auto ack of transient alarms on enable"); + cdata->unackSevr = NO_ALARM; + } + } + } + } + + if (mask.Ack != cdata->curMask.Ack) { + alUpdateGroupMask(clink,ALARMACK,mask.Ack); + + cdata->curMask.Ack = mask.Ack; + + change = 1; + if (mask.Ack == 1 ) { + if (cdata->unackSevr > 0 ) { + unackSevrHold = cdata->unackSevr; + alSetUnackSevChan(clink,NO_ALARM); + if (_global_flag) cdata->unackSevr = unackSevrHold; + } + } + + if (mask.Ack == 0 && mask.Cancel ==0 && mask.Disable == 0) { + if (cdata->curSevr > 0 ) { + /* + * update unackSev[] of all parent groups + */ + if (_global_flag){ + unackSevrHold = cdata->unackSevr; + cdata->unackSevr = NO_ALARM; + alSetUnackSevChan(clink,unackSevrHold); + } else { + alSetUnackSevChan(clink,cdata->curSevr); + } + /* + * reset silenceCurrent state to FALSE + */ + if (psetup.silenceCurrent && + (psetup.newUnackBeepSevr>=psetup.beepSevr) ) + silenceCurrentReset(clink->pmainGroup->area); + } else { + if (cdata->unackSevr > 0 && _global_flag ) { + ackChan(clink); + alLogOpModMessage(0,(GCLINK*)clink,"Auto ack of transient alarms"); + cdata->unackSevr = NO_ALARM; + } + } + } + } + + if (mask.AckT != cdata->curMask.AckT) { + alUpdateGroupMask(clink,ALARMACKT,mask.AckT); + cdata->curMask.AckT = mask.AckT; + change = 1; + if (_global_flag && !_passive_flag) { + /* NOTE: ackt and curMask.AckT have opposite meaning */ + short ackt = (mask.AckT+1)%2; + alCaPutGblAckT(cdata->chid,&ackt); + } + } + + if (mask.Log != cdata->curMask.Log) { + alUpdateGroupMask(clink,ALARMLOG,mask.Log); + cdata->curMask.Log = mask.Log; + change = 1; + } + + + /* + * set current mask to new mask + */ + + if (change == 1) { + clink->modified = 1; + clink->pmainGroup->modified = TRUE; + } + + + +} + +/*********************************************************************** + * This function changes the mask of all the channels in a group to new mask. + ***********************************************************************/ +void alChangeGroupMask(GLINK *glink,MASK mask) +{ + CLINK *clink; + GLINK *subgroup; + SNODE *pt; + + if (glink == NULL) return; + /* + * change each channel's mask to new mask + */ + + pt = sllFirst(&glink->chanList); + while (pt) { + clink = (CLINK *)pt; + alChangeChanMask(clink,mask); + pt = sllNext(pt); + } + + /* + * change each subgroup's mask to new mask + */ + + pt = sllFirst(&glink->subGroupList); + while (pt) { + subgroup = (GLINK *)pt; + alChangeGroupMask(subgroup,mask); + pt = sllNext(pt); + } + +} + +/*********************************************************************** + * This function changes the mask of all the channels in a group to new mask. + ***********************************************************************/ +void alResetGroupMask(GLINK *glink) +{ + CLINK *clink; + GLINK *subgroup; + SNODE *pt; + MASK mask; + + if (glink == NULL) return; + /* + * change each channel's mask to the reset mask + */ + + pt = sllFirst(&glink->chanList); + while (pt) { + clink = (CLINK *)pt; + mask = clink->pchanData->defaultMask; + alChangeChanMask(clink,mask); + pt = sllNext(pt); + } + + /* + * change each subgroup's mask to new mask + */ + + pt = sllFirst(&glink->subGroupList); + while (pt) { + subgroup = (GLINK *)pt; + alResetGroupMask(subgroup); + pt = sllNext(pt); + } + +} + +/*************************************************** + alAlarmGroupName +****************************************************/ +char *alAlarmGroupName(GLINK *link) +{ + if (link){ + if (link->pgroupData->alias) return(link->pgroupData->alias); + else return(link->pgroupData->name); + } + return(0); +} + +/*************************************************** + alProcessExists +****************************************************/ +int alProcessExists(GCLINK *link) +{ + if (link->pgcData->command) return(TRUE); + return(FALSE); +} + +/*************************************************** + alSetUnackSevGroup +****************************************************/ +static void alSetUnackSevGroup(GLINK *glink,int newSevr,int oldSevr) +{ + struct groupData * gdata; + + gdata = (struct groupData *)glink->pgroupData; + gdata->unackSev[oldSevr]--; + gdata->unackSev[newSevr]++; + gdata->unackSevr = alHighestSeverity(gdata->unackSev); + glink->modified = 1; + if (glink->parent) alSetUnackSevGroup(glink->parent,newSevr,oldSevr); +} + +/*************************************************** + alSetUnackBeepSevGroup +****************************************************/ +static void alSetUnackBeepSevGroup(GLINK *glink,int newSevr,int oldSevr) +{ + struct groupData * gdata; + int osev=0; + int nsev=0; + + gdata = (struct groupData *)glink->pgroupData; + gdata->unackBeepSev[oldSevr]--; + gdata->unackBeepSev[newSevr]++; + gdata->unackBeepSevr = alHighestBeepSeverity(gdata->unackBeepSev,gdata->beepSevr); + if (oldSevr >= gdata->beepSevr) osev=oldSevr; + if (newSevr >= gdata->beepSevr) nsev=newSevr; + if (glink->parent) alSetUnackBeepSevGroup(glink->parent,nsev,osev); + else psetup.newUnackBeepSevr=nsev; +} + +/*************************************************** + alSetUnackSevChan +****************************************************/ +void alSetUnackSevChan(CLINK *clink,int newSevr) +{ + int oldSevr; + int osev=0; + int nsev=0; + + oldSevr = clink->pchanData->unackSevr; + if (oldSevr == newSevr) return; + clink->pchanData->unackSevr = newSevr; + clink->modified = 1; + clink->pmainGroup->modified = TRUE; + clink->pchanData->unackBeepSevr = newSevr; + if (clink->parent) alSetUnackSevGroup(clink->parent,newSevr,oldSevr); + if (oldSevr >= clink->pchanData->beepSevr) osev=oldSevr; + if (newSevr >= clink->pchanData->beepSevr) nsev=newSevr; + if (clink->parent) alSetUnackBeepSevGroup(clink->parent,nsev,osev); +} + + +/*************************************************** + alSetBeepSevrChan +****************************************************/ +void alSetBeepSevrChan(CLINK *clink,int beepSevr) +{ + int oldBeepSevr; + int sev=0; + int osev=0; + int nsev=0; + + if (clink->pchanData->beepSevr == beepSevr) return; + oldBeepSevr = clink->pchanData->beepSevr; + clink->pchanData->beepSevr = beepSevr; + clink->pchanData->highestBeepSevr = beepSevr; + clink->modified = 1; + clink->pmainGroup->modified = TRUE; + if (clink->parent) alSetBeepSevCount(clink->parent,beepSevr,oldBeepSevr); + sev = clink->pchanData->unackSevr; + if (sev >= oldBeepSevr) osev=sev; + if (sev >= beepSevr) nsev=sev; + if (osev == nsev) return; + if (clink->parent) alSetUnackBeepSevGroup(clink->parent,nsev,osev); +} + + +/*************************************************** + alSetUnackBeepSevCountGroup +****************************************************/ +static void alSetUnackBeepSevCountGroup(GLINK *glink,int newSevr,int oldSevr,int count) +{ + struct groupData * gdata; + int osev=0; + int nsev=0; + + gdata = (struct groupData *)glink->pgroupData; + gdata->unackBeepSev[oldSevr]=gdata->unackBeepSev[oldSevr] - count; + gdata->unackBeepSev[newSevr]=gdata->unackBeepSev[newSevr] + count; + + gdata->unackBeepSevr = alHighestBeepSeverity(gdata->unackBeepSev,gdata->beepSevr); + if (oldSevr >= gdata->beepSevr) osev=oldSevr; + if (newSevr >= gdata->beepSevr) nsev=newSevr; + if (glink->parent) alSetUnackBeepSevCountGroup(glink->parent,nsev,osev,count); + else psetup.newUnackBeepSevr=nsev; +} + +/*************************************************** + alSetBeepSevrGroup +****************************************************/ +void alSetBeepSevrGroup(GLINK *glink,int beepSevr) +{ + struct groupData * gdata; + int oldBeepSevr; + int i, count; + int osev, nsev; + int start, end; + + gdata = (struct groupData *)glink->pgroupData; + oldBeepSevr = gdata->beepSevr; + if (oldBeepSevr == beepSevr) return; + gdata->beepSevr = beepSevr; + alSetBeepSevCount(glink,beepSevr,oldBeepSevr); + gdata->unackBeepSevr = alHighestBeepSeverity(gdata->unackBeepSev,gdata->beepSevr); + glink->modified = 1; + glink->pmainGroup->modified = TRUE; + if ( oldBeepSevr < beepSevr) { start=oldBeepSevr; end=beepSevr; } + else { start=beepSevr; end=oldBeepSevr; } + for (i=start; iunackSev[i]; + osev=0; + nsev=0; + if (i >= oldBeepSevr) osev=i; + if (i >= beepSevr) nsev=i; + if (glink->parent && osev != nsev ) alSetUnackBeepSevCountGroup(glink->parent,nsev,osev,count); + } +} + + +/*************************************************** + alSetBeepSevCount +****************************************************/ +static void alSetBeepSevCount(GLINK *glink,int newBeepSevr,int oldBeepSevr) +{ + struct groupData * gdata; + + while (glink) { + gdata = glink->pgroupData; + if (oldBeepSevr>=MINOR_ALARM) gdata->beepSev[oldBeepSevr]--; + if (newBeepSevr>=MINOR_ALARM) gdata->beepSev[newBeepSevr]++; + gdata->highestBeepSevr=alHighestSeverity(gdata->beepSev); + glink->modified = 1; + glink = glink->parent; + } +} + + +/*************************************************** + set new channel unacknowledge transients setting +****************************************************/ +void alSetAckTChan(CLINK *clink,int newAckT) +{ + struct chanData *cdata; + int oldAckT; + + cdata = clink->pchanData; + + oldAckT = cdata->curMask.AckT; + if (oldAckT == newAckT) return; + + if (newAckT == FALSE && (cdata->unackSevr > cdata->curSevr)) { + if (!_global_flag || + ( cdata->curMask.Disable == 0 && cdata->curMask.Ack == 0 ) ) { + alSetUnackSevChan(clink,cdata->curSevr); + } + } + + alUpdateGroupMask(clink,ALARMACKT,newAckT); + cdata->curMask.AckT = newAckT; + + clink->modified = 1; + clink->pmainGroup->modified = TRUE; +} + + + +/************************************************************************** + * This function checks each bit of the new mask against to the current + * mask. If the bit of mask to be changed then call alUpdateGroupMask + * to update the parent group mask. Finally updates current channel mask. + **************************************************************************/ +void alSetCurChanMask(CLINK *clink,MASK mask) +{ + struct chanData *cdata; + cdata = clink->pchanData; + + if (mask.Cancel != cdata->curMask.Cancel) { + alUpdateGroupMask(clink,ALARMCANCEL,mask.Cancel); + cdata->curMask.Cancel = mask.Cancel; + } + if (mask.Disable != cdata->curMask.Disable) { + alUpdateGroupMask(clink,ALARMDISABLE,mask.Disable); + cdata->curMask.Disable = mask.Disable; + } + if (mask.Ack != cdata->curMask.Ack) { + alUpdateGroupMask(clink,ALARMACK,mask.Ack); + cdata->curMask.Ack = mask.Ack; + } + if (mask.AckT != cdata->curMask.AckT) { + alUpdateGroupMask(clink,ALARMACKT,mask.AckT); + cdata->curMask.AckT = mask.AckT; + } + if (mask.Log != cdata->curMask.Log) { + alUpdateGroupMask(clink,ALARMLOG,mask.Log); + cdata->curMask.Log = mask.Log; + } +} + +/************************************************************************* + *Remove the noAck timer for a channel + **********************************************************************/ +void alRemoveNoAck1HrTimerChan(CLINK *clink) +{ + if (clink->pchanData->noAckTimerId){ + XtRemoveTimeOut(clink->pchanData->noAckTimerId); + clink->pchanData->noAckTimerId = 0; + } +} + +/************************************************************************* + *Remove the noAck timer for group and group's channels and subgroups + **********************************************************************/ +void alRemoveNoAck1HrTimerGroup(GLINK *glink) +{ + GLINK *group; + CLINK *clink; + SNODE *pt; + + if (glink->pgroupData->noAckTimerId){ + XtRemoveTimeOut(glink->pgroupData->noAckTimerId); + glink->pgroupData->noAckTimerId = 0; + } + /* + * for all channels in this group + */ + pt = sllFirst(&(glink->chanList)); + while (pt) { + clink = (CLINK *)pt; + alRemoveNoAck1HrTimerChan(clink); + pt = sllNext(pt); + } + /* + * for all subgroups + */ + pt = sllFirst(&(glink->subGroupList)); + while (pt) { + group = (GLINK *)pt; + alRemoveNoAck1HrTimerGroup(group); + pt = sllNext(pt); + } +} + diff --git a/alLib.h b/alLib.h new file mode 100644 index 0000000..1924e5b --- /dev/null +++ b/alLib.h @@ -0,0 +1,224 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alLib.h */ + +/************************DESCRIPTION*********************************** + Group and channel data structure definitions +**********************************************************************/ + +#ifndef INCalLibh +#define INCalLibh 1 + +#include "cadef.h" + +#include "alh.h" +#include "sllLib.h" +#include "ellLib.h" + +typedef struct mask { /* mask bit setting */ + unsigned Cancel : 1; + unsigned Disable : 1; + unsigned Ack : 1; + unsigned AckT : 1; + unsigned Log : 1; + unsigned Unused : 11; +} MASK; + +typedef struct alarmEvent { + short stat; + short sevr; + short acks; + short ackt; + char value[MAX_STRING_SIZE]; + int alarmTime; + void *clink; +} ALARMEVENT; + +typedef struct countFilter { + int inputCount; + int inputSeconds; + short stat; /* channel status from CA */ + short sev; /* current severity */ + short acks; /* highest unack severity */ + short ackt; /* acknowledge transients? */ + char value[MAX_STRING_SIZE]; /* channel value from CA */ + int countIndex; + int alarmTime; + time_t *alarmTimeHistory; + void *clink; + XtIntervalId timeoutId; +} COUNTFILTER; + +typedef struct forcePVdata { + short index; + void *link; + short linktype; +} FORCEPVCADATA; + +#ifndef NO_OF_CALC_PVS +#define NO_OF_CALC_PVS 6 +#endif + +typedef struct calc { + char *expression; /* calc expression */ + char *rpbuf; /* calc expression in reverse polish */ + char *name[NO_OF_CALC_PVS]; /* pv name */ + chid chid[NO_OF_CALC_PVS]; /* pv channel id */ + evid evid[NO_OF_CALC_PVS]; /* pv event id */ + FORCEPVCADATA* puser[NO_OF_CALC_PVS]; /* pv current value */ + double value[NO_OF_CALC_PVS]; /* pv current value */ +} FORCEPV_CALC; + +typedef struct forcePV { + char *name; /* pv name */ + chid chid; /* pv channel id */ + evid evid; /* pv channel event id */ + FORCEPVCADATA* puser; /* pv current value */ + double currentValue; /* pv current value */ + double forceValue; /* pv value for force mask */ + double resetValue; /* pv value for reset mask */ + short disabled; /* pv disabled? TRUE/FALSE */ + MASK forceMask; /* force mask */ + FORCEPV_CALC* pcalc; +} FORCEPV; + +/* group/channel data structure */ +struct gcData { + char *name; /* group name */ + char *sevrPVName; /* severityPV name */ + FORCEPV *pforcePV; /* forcePV info */ + char *alias; /* alias text */ + char *command; /* command text */ + ELLLIST sevrCommandList; /* alarm severity command list */ + short curSevr; /* current severity */ + short unackSevr; /* highest unack severity */ + short unackBeepSevr; /* highest unack severity for beeping */ + short highestBeepSevr; /* highest beep severity */ + chid sevrchid; /* sevrPV channel id */ + short beepSevr; /* beep severity */ + XtIntervalId noAckTimerId; +}; + +/* group data structure */ +struct groupData { + char *name; /* group name */ + char *sevrPVName; /* severityPV name */ + FORCEPV *pforcePV; /* forcePV info */ + char *alias; /* alias text */ + char *command; /* command text */ + ELLLIST sevrCommandList; /* severity command list */ + short curSevr; /* current highestseverity from CA */ + short unackSevr; /* highest unack severity */ + short unackBeepSevr; /* highest unack severity for beeping */ + short highestBeepSevr; /* highest beep severity */ + chid sevrchid; /* group sevrPV channel id */ + short beepSevr; /* beep severity */ + XtIntervalId noAckTimerId; + char *treeSym; /* tree symbols for treeWindow display */ + int mask[ALARM_NMASK]; /* no. of channels of masked types*/ + int beepSev[ALH_ALARM_NSEV]; /* channels of different beep severity */ + int curSev[ALH_ALARM_NSEV]; /* channels of different severity */ + int unackSev[ALH_ALARM_NSEV]; /* channels of unacknowledged sevr */ + int unackBeepSev[ALH_ALARM_NSEV]; /* channels of unacknowledged sev >= beep sevr */ +}; + +/* channel data structure */ +struct chanData { + char *name; /* channel name, or device/attribute */ + char *sevrPVName; /* severityPV name */ + FORCEPV *pforcePV; /* forcePV info */ + char *alias; /* alias text */ + char *command; /* command text */ + ELLLIST sevrCommandList; /* severity command list */ + short curSevr; /* channel severity from CA */ + short unackSevr; /* highest unack severity */ + short unackBeepSevr; /* highest unack severity for beeping */ + short highestBeepSevr; /* highest beep severity */ + chid sevrchid; /* sevrPV channel id */ + short beepSevr; /* beep severity */ + XtIntervalId noAckTimerId; + ELLLIST statCommandList; /* alarm status command list */ + COUNTFILTER *countFilter; /* alarm count filter */ + MASK curMask; /* current mask setting */ + MASK defaultMask; /* default mask setting */ + char value[MAX_STRING_SIZE]; /* channel value from CA */ + short curStat; /* channel status from CA */ + chid chid; /* chid from CA search */ + evid evid; /* evid from CA add event */ + char *description; /* Info from PV .DESC field */ + chid descriptionId; /* his (.DESC) chid */ + char *ackPVName; /* ackPV name */ + chid ackPVId; /* id of prev. */ + short ackPVValue; /* value to ackPV */ + ALARMEVENT caAlarmEvent; /* saved ca alarm event data */ +}; + +/* group link */ +struct groupLink { + SNODE node; /* single link list node type */ + SLIST GuideList; /* guidance link list */ + char *guidanceLocation; /* guidance location (url or filename)*/ + struct groupLink *parent; /* parent groupLink pointer */ + struct groupData *pgroupData; /* group data pointer */ + struct mainGroup *pmainGroup; /* mainGroup pointer */ + void *lineTreeW; /* line address Tree Window*/ + void *lineGroupW; /* line address Group Window*/ + int viewCount; /* count of open groups */ + int modified; /* modified indicator */ + SLIST subGroupList; /* subgroup link list */ + SLIST chanList; /* channel link list */ +}; + +/* channel link */ +struct chanLink { + SNODE node; /* single link list node type */ + SLIST GuideList; /* guidance link list */ + char *guidanceLocation; /* guidance location (url or filename)*/ + struct groupLink *parent; /* parent groupLinke pointer */ + struct chanData *pchanData; /* channel data pointer */ + struct mainGroup *pmainGroup; /* mainGroup pointer */ + void *lineTreeW; /* line address Tree Window*/ + void *lineGroupW; /* line address Group Window*/ + int viewCount; /* open/closed indicator */ + int modified; /* modified indicator */ + +}; + +/* any link */ +struct anyLink { + SNODE node; /* single link list node type */ + SLIST GuideList; /* guidance link list */ + char *guidanceLocation; /* guidance location (url or filename)*/ + struct groupLink *parent; /* parent groupLink pointer */ + struct gcData *pgcData; /* channel data pointer */ + struct mainGroup *pmainGroup; /* mainGroup pointer */ + void *lineTreeW; /* line address Tree Window*/ + void *lineGroupW; /* line address Group Window*/ + int viewCount; /* open/closed count or indicator */ + int modified; /* modified indicator */ +}; + +/* guidance link */ +struct guideLink { + SNODE node; /* single link list node type */ + char *list; /* guidance list address */ +}; + +typedef struct groupLink GLINK; +typedef struct chanLink CLINK; +typedef struct anyLink GCLINK; + +#endif /* INCalLibh */ + diff --git a/alLog.c b/alLog.c new file mode 100644 index 0000000..b09e92a --- /dev/null +++ b/alLog.c @@ -0,0 +1,658 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alLog.c */ + +/************************DESCRIPTION*********************************** + Routines for logging messages +**********************************************************************/ + + +#include +#include +#include +#include +#include "alh.h" +#ifdef HAVE_SYSV_IPC +#include +#endif + + +#ifdef CMLOG +#include +#endif + +#include "ax.h" +#if 0 +#include "alh.h" +#include "alLib.h" +#include "line.h" +#endif +#include +#if (EPICS_VERSION <= 3) && (EPICS_REVISION <= 13) +#include "truncateFile.h" +#else +#include +#endif + +extern int DEBUG; +extern int _DB_call_flag; +extern int _global_flag; +extern int _lock_flag; +extern int _description_field_flag; +extern int _message_broadcast_flag; +extern int _printer_flag; /* Printer flag. Albert */ +extern int _read_only_flag; /* RO flag. Albert */ +extern int _time_flag; /* Dated flag. Albert */ +extern int _xml_flag; /* Use XML-ish log format. SNS */ +extern char * alhAlarmSeverityString[]; +extern const char *ackTransientsString[]; +extern char * alhAlarmStatusString[]; +extern int DBMsgQId; +extern int masterFlag; +extern int notsave; +extern int printerMsgQId; +extern int tm_day_old; /* Midnight switch. Albert */ + +extern struct UserInfo userID; /* info about current operator */ +extern char applicationName[64]; /* Albert1 applicationName = mainGroupName will be send to DB */ +extern char deviceName[64]; /* Albert1 reserved; will be send to DB */ + +#ifdef CMLOG + /* CMLOG flags & variables */ +extern int use_CMLOG_alarm; +extern int use_CMLOG_opmod; +cmlog_client_t cmlog; +#endif +extern ALINK *alhArea; + +const char *masksdata[] = { + "Add / Cancel", + "Enable / Disable", + "Ack / NoAck", + "Ack / NoAck Transient", + "Log / NoLog " +}; +const char *mask_str[3] = {"OFF", "ON", "RESET"}; + +struct setup psetup = { /* initial files & beeping setup */ + "", /* config file name */ + "", /* alarm log file name */ + "", /* opMod log file name */ + "", /* save config file name */ + 0, /* silenceForever */ + 0, /* silenceOneHour */ + 0, /* silenceCurrent */ + 1, /* 1,2,3,4,5 */ + 0, /* system highest sevr */ + 0, /* system highest unack sevr */ + 0, /* config files directory */ + 0}; /* log files directory */ + +int alarmLogFileMaxRecords = 2000; /* alarm log file maximum # records */ +int alarmLogFileOffsetBytes = 0; /* alarm log file current offset in bytes */ +const char alarmLogFileEndString[] = " "; /* alarm log file end of data string */ +int alarmLogFileStringLength = 158; /* alarm log file record length*/ + +FILE *fo=0; /* write opmod file pointer */ +FILE *fl=0; /* write alarm log file pointer */ + +char buff[260]; + +const char *digit2month[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug", + "Sep","Oct","Nov","Dec"}; + +struct UserInfo { +char *loginid; +char *real_world_name; +char *myhostname; +char *displayName; +}; +#if 0 + + +#define REGULAR_RECORD 1 /* usual alLog mess. */ +#define CONNECT_ALARM 2 /* specific alLog format about connection lost */ +#define STOP_LOGGING_ALARM 3 /* specific alLog format about stopping loging */ +#define MESSAGE_QUEUE_ALARM 4 /* specific alLog format about MQ problems */ +#define ACK_CHANNEL 5 /* op_mod action which will be saving in DB */ +#define ACK_GROUP 6 /* Don't used now */ +#define CHANGE_MASK 7 /* op_mod action which will be saving in DB */ +#define CHANGE_MASK_GROUP 8 /* op_mod action which will be saving in DB */ +#define FORCE_MASK 9 /* op_mod action which will be saving in DB */ +#define FORCE_MASK_GROUP 10 /* op_mod action which will be saving in DB */ +#define ALARM_LOG_DB 1 /* We are write to ALARM_LOG database */ +#define OP_MOD_DB 2 /* We are write to OP_MOD database */ + +#endif + +int filePrintf(FILE *fPointer,char *buf,time_t *ptime,int typeOfRecord); +#ifdef HAVE_SYSV_IPC +int write2MQ(int, char *); +int write2msgQ(int, char *); +#endif + +#ifdef CMLOG +/*********************************************************************** + * open the CMLOG connection + ***********************************************************************/ +void alCMLOGconnect(void) +{ + cmlog = cmlog_open("alh"); +} + +/*********************************************************************** + * close the CMLOG connection + ***********************************************************************/ +void alCMLOGdisconnect(void) +{ + cmlog_close(cmlog); +} +#endif + +/*********************************************************************** + * log channel alarm to the alarm logfile + ***********************************************************************/ +void alLogAlarmMessage(time_t *ptimeofdayAlarm,int messageCode,CLINK* clink,const char* fmt,...) +{ + va_list vargs; + static char text[1024]; /* DANGER: Fixed buffer size */ + struct chanData *cdata; + + if (clink == NULL ) return; + cdata = clink->pchanData; + if (cdata == NULL ) return; + + va_start(vargs,fmt); + vsprintf(text,fmt,vargs); + va_end(vargs); + + if(text[0] == '\0') sprintf(text," "); + +#ifdef CMLOG + cmlog_logmsg(cmlog, + 0, /* verbosity */ + 0, /* dummy severity */ + messageCode, /* code */ + "Alarm", /* facility */ + "status=%s severity=%s device=%s message=%s " + "text=%s domain=%s value=%s", + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr], + cdata->name, + cdata->name, + (cdata->alias ? cdata->alias : "N/A"), + text, + (alhArea ? alhArea->blinkString : "N/A"), + cdata->value); +#endif + if (_xml_flag) /* Use XML-ish entries which are easier to parse. SNS */ + { + if (!_description_field_flag) + { + if (_global_flag) + sprintf(buff, + "%s %s %s %s %s %s", + cdata->name, cdata->value, + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr], + alhAlarmSeverityString[cdata->unackSevr], + ackTransientsString[cdata->curMask.AckT]); + else + sprintf(buff, + "%s %s %s %s", + cdata->name, cdata->value, + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr]); + } + else + { /* _description_field_flag is ON */ + if (_global_flag) + sprintf(buff, + "%s %s %s %s %s %s %s", + cdata->name,cdata->description,cdata->value, + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr], + alhAlarmSeverityString[cdata->unackSevr], + ackTransientsString[cdata->curMask.AckT]); + else + sprintf(buff, + "%s %s %s %s %s", + cdata->name,cdata->description,cdata->value, + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr]); + } + } + else /* Original, non-XMLish format */ + { + if (!_description_field_flag) + { + if (_global_flag) + sprintf(buff, "%-28s %-12s %-16s %-12s %-5s %-40.40s\n", + cdata->name, + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr], + alhAlarmSeverityString[cdata->unackSevr], + ackTransientsString[cdata->curMask.AckT], + cdata->value); + else + sprintf(buff, "%-28s %-12s %-16s %-40.40s\n", + cdata->name, + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr], + cdata->value); + } + else + { /* _description_field_flag is ON */ + if (_global_flag) + sprintf(buff, "%-28s %-28s %-40.40s %-12s %-16s %-12s %-5s\n", + cdata->name,cdata->description,cdata->value, + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr], + alhAlarmSeverityString[cdata->unackSevr], + ackTransientsString[cdata->curMask.AckT]); + else + sprintf(buff, "%-28s %-28s %-40.40s %-12s %-16s\n", + cdata->name,cdata->description,cdata->value, + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr]); + } + } + filePrintf(fl,buff,ptimeofdayAlarm,messageCode); +} + + +/*********************************************************************** + * log operator changes to the opMod logfile + ***********************************************************************/ +void alLogOpModMessage(int messageCode,GCLINK* gclink,const char* fmt,...) +{ + va_list vargs; + static char text[1024]; /* DANGER: Fixed buffer size */ + struct gcData *gcdata=NULL; + + if (gclink) gcdata = gclink->pgcData; + + va_start(vargs,fmt); + vsprintf(text,fmt,vargs); + va_end(vargs); + + if(text[0] == '\0') sprintf(text," "); + +#ifdef CMLOG + if (use_CMLOG_opmod) { + + if (!gcdata) return; + cmlog_logmsg(cmlog, + 2, /* verbosity */ + 0, /* dummy severity */ + messageCode, /* code */ + "Opmod", /* facility */ + "device=%s message=%s text=%s domain=%s", + gcdata->name, + (gcdata->alias ? gdata->alias : "N/A"), + cm_text, + (alhArea ? alhArea->blinkString : "N/A")); + } +#endif + + if (!alhArea || !alhArea->blinkString){ + sprintf(buff,"%s",text); + } else { + if (!gcdata){ + sprintf(buff,"%s: : %s",alhArea->blinkString,text); + } else { + sprintf(buff,"%s: %s: %s",alhArea->blinkString,gcdata->name,text); + } + } + + filePrintf(fo,buff,NULL,messageCode); +} + + +/*********************************************************************** + * log operator changes to the opMod logfile + ***********************************************************************/ +void alLogOpModAckMessage(int messageCode,GCLINK* gclink,const char* fmt,...) +{ + va_list vargs; + static char text[1024]; /* DANGER: Fixed buffer size */ + struct gcData *gcdata=NULL; + + if (gclink) gcdata = gclink->pgcData; + + va_start(vargs,fmt); + vsprintf(text,fmt,vargs); + va_end(vargs); + + if(text[0] == '\0') sprintf(text," "); + +#ifdef CMLOG + if (use_CMLOG_opmod) { + + if (!gcdata) return; + cmlog_logmsg(cmlog, + 1, /* verbosity */ + 0, /* dummy severity */ + messageCode, /* code */ + "Opmod", /* facility */ + "severity=%s device=%s message=%s text=%s domain=%s", + alhAlarmSeverityString[gcdata->curSevr], + gcdata->pname, + (gcdata->alias ? gcdata->alias : "N/A"), + cm_text, + (alhArea ? alhArea->blinkString : "N/A")); + } +#endif + + if (!alhArea || !alhArea->blinkString){ + sprintf(buff," : : %s \n",text); + } else { + if (!gcdata){ + sprintf(buff,"%s: : %s %-16s",alhArea->blinkString,text, + alhAlarmSeverityString[gcdata->curSevr]); + } else { + sprintf(buff,"%s: %s: %s %-16s",alhArea->blinkString,gcdata->name,text, + alhAlarmSeverityString[gcdata->curSevr]); + } + } + + filePrintf(fo,buff,NULL,messageCode); +} + + +/*********************************************************************** + * log not_save started to alarm log file + ***********************************************************************/ +void alLogNotSaveStart(int not_save_time) +{ + sprintf(buff,"Stop log start during %d min",not_save_time); + filePrintf(fl,buff,NULL,STOP_LOGGING_ALARM); +} + +/*********************************************************************** + * log not_save started to alarm log file + ***********************************************************************/ +void alLogNotSaveFinish() +{ + sprintf(buff,"Stop log finish"); + filePrintf(fl,buff,NULL,STOP_LOGGING_ALARM); +} + +/*********************************************************************** + * log ackchan in special format on operation file and DB (need for forse +save all recordName if someone acknowledges group) + ***********************************************************************/ + + +void alLog2DBAckChan (char *name) +{ + sprintf(buff,"Ack Channel--- %-28s",name); + filePrintf(fo,buff,NULL,ACK_GROUP); /* update the file */ +} + +/*********************************************************************** + * log changeMask in special format on operation file and DB (need for forse +save all recordName if someone acknowledges group) + ***********************************************************************/ +void alLog2DBMask (char *name) +{ + sprintf(buff,"Group Mask ID --- %-28s",name); + filePrintf(fo,buff,NULL,CHANGE_MASK_GROUP); /* update the file */ +} + + +/********************************************************************** + Write info to HardDisk OpMod and AlarmLog files + +operations: +1) add timeString before buffer +2) fprintf(FILE); +3) then fflush it +4) and updateLog/updateAlarmLog + ++ checking for non-overriting (master/slave) ++ if _DB_flag write info to DB ++ if _printer_flag write info to printer ++ if _time_flag and midnight change AlarmLog and OpMod extension +Parameters: 1) filePointer +2) Buffer +3) TimePointer (If we use (very often) current time = NULL ) +4) Special flag for distinguish usual format of alarm (type =REGULAR_RECORD=0) + and unusual (type = {CONNECT_ALARM,STOP_LOGGING_ALARM...} + +***********************************************************************/ + +int filePrintf(FILE *fPointer,char *buf,time_t *ptime,int typeOfRecord) +{ + int ret=0; + int status; + static char bufSave[1024]; + static char DBbuff[1024]; + struct tm *tms; + char buf_tmp[1024]; + time_t timeofday; + + if(!fPointer) return (-1); + + if((!masterFlag) && (fPointer==fl)) return (0); + if(_message_broadcast_flag && notsave && (fPointer==fl) ) return (0); + + if (ptime == NULL) /* Current time */ + { + timeofday = time(0L); + tms = localtime(&timeofday); + } + else tms = localtime(ptime); /* Calculate time from event */ + + + /*______ For AlLog dated __________________________________________ */ + if (_time_flag) + { + if(tms->tm_mday != tm_day_old) + { + sprintf(buf_tmp,".%.4d-%.2d-%.2d", + 1900+tms->tm_year,1+tms->tm_mon,tms->tm_mday); + buf_tmp[11]=0; + + psetup.logFile[strlen(psetup.logFile) - 11] = 0; + strncat(psetup.logFile, buf_tmp, strlen(buf_tmp)); + fclose(fl); + fl = fopen(psetup.logFile,"a"); + fclose(fl); + if(_read_only_flag) fl = fopen(psetup.logFile,"r"); + else if (_lock_flag) fl = fopen(psetup.logFile,"a"); + else fl = fopen(psetup.logFile,"r+"); + + /* The same with psetup.opModFile: */ + psetup.opModFile[strlen(psetup.opModFile) - 11] = 0; + strncat(psetup.opModFile, buf_tmp, strlen(buf_tmp)); + fclose(fo); + fo = fopen(psetup.opModFile,"a"); + fclose(fo); + if(_read_only_flag) fo = fopen(psetup.opModFile,"r"); + else if (_lock_flag) fo = fopen(psetup.opModFile,"a"); + else fo = fopen(psetup.opModFile,"r+"); + + tm_day_old=tms->tm_mday; + alarmLogFileOffsetBytes =0; + } + } + /*________________________ end for AlLog dated ______________________ */ + + /* Time format (like "09-Feb-1999 12:21:12"): */ + if (_xml_flag) + { + sprintf(buf_tmp,"%-.2d-%-3s-%-.4d ", + tms->tm_mday,digit2month[tms->tm_mon],1900+tms->tm_year, + tms->tm_hour,tms->tm_min,tms->tm_sec); + sprintf(bufSave,"%s %s\n",buf_tmp,buf); + } + else + { + sprintf(buf_tmp,"%-.2d-%-3s-%-.4d %-.2d:%-.2d:%-.2d", + tms->tm_mday,digit2month[tms->tm_mon],1900+tms->tm_year, + tms->tm_hour,tms->tm_min,tms->tm_sec); + buf_tmp[20]=0; + sprintf(bufSave,"%-20s : %s\n",buf_tmp,buf); + } + if (alarmLogFileMaxRecords&&(fPointer==fl)) + { + if (alarmLogFileOffsetBytes != ftell(fl)) + fseek(fl,alarmLogFileOffsetBytes,SEEK_SET); + if (alarmLogFileOffsetBytes >= alarmLogFileStringLength*alarmLogFileMaxRecords) { + rewind(fl); + status=truncateFile(psetup.logFile,alarmLogFileOffsetBytes); + alarmLogFileOffsetBytes = 0; + } + } + + + ret=fprintf(fPointer,"%s",bufSave); + + if (ret<0 && !_read_only_flag) { + fprintf(stderr,"Can't write '%s' to file=%s!!!\n", + bufSave,(fPointer==fl)?"LOGfile":"OpModFile" ); + } + + if (alarmLogFileMaxRecords&&(fPointer==fl)){ + if (!alarmLogFileOffsetBytes) alarmLogFileStringLength=ftell(fl); + alarmLogFileOffsetBytes = ftell(fl); + } + + fflush(fPointer); + + + if(fPointer==fl) updateAlarmLog(ALARM_FILE,bufSave); + else if (fPointer==fo) updateLog (OPMOD_FILE,bufSave); + else fprintf(stderr,"\nBad fPointer for writing\n"); + + if( (_printer_flag) && (fPointer==fl) &&printerMsgQId ) + { + sprintf(DBbuff,"%d %d %s %s",ALARM_LOG_DB, typeOfRecord+1,buf_tmp,buff); +#ifdef HAVE_SYSV_IPC + write2MQ(printerMsgQId, DBbuff); +#endif + } + + if(_DB_call_flag && DBMsgQId ) + { + if (fPointer==fo) /* write into AlarmOp Database */ + { + if(typeOfRecord ==0) return(ret); + sprintf(DBbuff,"%d %d %s %s %s %s %s %s %s",OP_MOD_DB,typeOfRecord,applicationName, + deviceName,userID.loginid,userID.myhostname,userID.displayName,buf_tmp,buff); + } + else if (fPointer==fl) /* write into AlarmLOG Database */ + { + if(typeOfRecord ==0) return(ret); + sprintf(DBbuff,"%d %d %s %s %s %s %s %s %s", ALARM_LOG_DB, typeOfRecord,applicationName, + deviceName,userID.loginid,userID.myhostname,userID.displayName,buf_tmp,buff); + } + else + { + fprintf(stderr,"\nBad fPointer for writing\n"); + return (ret); + } +#ifdef HAVE_SYSV_IPC + write2MQ(DBMsgQId, DBbuff); +#endif + } + +return (ret); +} + +/*********************************************************************** + Send alarm to message Queue for printer or DB. + After that it will be print in TCP-printer or save to DB. Albert +***********************************************************************/ + +#ifdef HAVE_SYSV_IPC +int write2MQ(int mq,char *message) +{ + char buf[256]; + static int lostFlag=0; + static int lostCount=0; + static time_t tFirst, tLast; + static char sFirst[32], sLast[32]; + time_t timeofday; + struct tm *tms; + static char buf_tmp[32]; + int ret; + + ret=write2msgQ(mq,message); + if (ret == 1 ) + { + if(!lostFlag) {tFirst=time(NULL);} + lostFlag=1; + tLast=time(NULL); + lostCount++; + if(DEBUG) printf("lostCount=%d\n",lostCount); + return(1); + } + else if (ret == - 1 ) return (-1); + else + { + if(lostFlag) + { + timeofday = time(0L); + tms = localtime(&timeofday); + sprintf(buf_tmp,"%-.2d-%-3s-%-.4d %-.2d:%-.2d:%-.2d", + tms->tm_mday,digit2month[tms->tm_mon],1900+tms->tm_year, + tms->tm_hour,tms->tm_min,tms->tm_sec); + buf_tmp[20]=0; + + tms = localtime(&tFirst); + sprintf(sFirst,"%-.2d-%-3s-%-.4d %-.2d:%-.2d:%-.2d", + tms->tm_mday,digit2month[tms->tm_mon],1900+tms->tm_year, + tms->tm_hour,tms->tm_min,tms->tm_sec); + sFirst[20]=0; + + tms = localtime(&tLast); + sprintf(sLast,"%-.2d-%-3s-%-.4d %-.2d:%-.2d:%-.2d", + tms->tm_mday,digit2month[tms->tm_mon],1900+tms->tm_year, + tms->tm_hour,tms->tm_min,tms->tm_sec); + sLast[20]=0; + + sprintf(buf,"%d %d %s %s %s %s %s %s MQ problem: MQ lost %d messages from=%s to=%s\n", + ALARM_LOG_DB,MESSAGE_QUEUE_ALARM, applicationName,deviceName, + userID.loginid,userID.myhostname,userID.displayName,buf_tmp, + lostCount+1,sFirst,sLast); + lostCount=0; + lostFlag=0; + + if(DEBUG) printf("after reconnect buf=%s\n",buf); + if (write2msgQ(mq,buf)== 1) /* bad connection with printer or DB*/ + { + perror("msgQsendError_is_very_unstable"); + return (1); + } + + } + } + return(0); +} + + +int write2msgQ(int mq, char *mes) +{ + if (msgsnd(mq,mes,strlen(mes),IPC_NOWAIT /* 0*/) == -1 ) + { + perror("msgQsendError"); + if(errno == EAGAIN ) return (1); /* Queue is full */ + return(-1); + } + return(0); +} +#endif diff --git a/alView.c b/alView.c new file mode 100644 index 0000000..310c008 --- /dev/null +++ b/alView.c @@ -0,0 +1,422 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alView.c */ + +/************************DESCRIPTIO************************************ + Routines for adjusting the tree view +**********************************************************************/ + +#include +#include +#include + +#include "sllLib.h" +#include "alLib.h" +#include "ax.h" + +/* forward declarations */ +static void treeView( GLINK *glink, int command, char *treeSym, int (*viewFilter)()); + + +/*************************************************** + Returns groupWindow viewCount for new glink +****************************************************/ +int alViewAdjustGroupW(GLINK *glink,int (*viewFilter)()) +{ + SNODE *pt; + int count=0; + + if (!glink) return(0); + pt = sllFirst(&glink->subGroupList); + while ( pt){ + if (glink->viewCount <= 1) + ((GCLINK *)pt)->viewCount = viewFilter((GCLINK *)pt); + if( ((GCLINK *)pt)->viewCount ) count++; + pt = sllNext(pt); + } + pt = sllFirst(&(glink->chanList)); + while (pt){ + ((GCLINK *)pt)->viewCount = viewFilter((GCLINK *)pt); + if( ((GCLINK *)pt)->viewCount ) count++; + pt = sllNext(pt); + } + return(count); +} + +/*************************************************** + Uses command to adjust treeW view at glink and return new viewCount +****************************************************/ +int alViewAdjustTreeW(GLINK *glink,int command,int (*viewFilter)()) +{ + GLINK *glinkTemp; + int holdViewCount, diffCount, count; + char treeSym[MAX_TREE_DEPTH+1]; + + memset(treeSym,'\0',MAX_TREE_DEPTH); + if (glink->pgroupData->treeSym) + strcpy(treeSym,glink->pgroupData->treeSym); + + + holdViewCount = glink->viewCount; + treeView(glink, command, treeSym, viewFilter); + diffCount = glink->viewCount - holdViewCount; + + glinkTemp=glink; + count = glinkTemp->viewCount; + while (glink){ + glinkTemp = glinkTemp->parent; + if (glinkTemp == NULL ) break; + glinkTemp->viewCount += diffCount; + count = glinkTemp->viewCount; + } + return(count); +} + +/*************************************************** + treeView +****************************************************/ +static void treeView(GLINK *glink,int command,char *treeSym,int (*viewFilter)()) +{ + SNODE *pt; + int subcommand; + int oldViewCount=0; + int length; + static char symMiddle={ + 0x15 }; + static char symContinue={ + 0x19 }; + static char symEnd={ + 0x0E }; + static char symBlank={ + 0x20 }; + static char symNull={ + 0x00 }; + + if (glink == NULL) return; + + if (command != NOCHANGE){ + oldViewCount = glink->viewCount; + glink->viewCount = viewFilter((GCLINK *)glink); + } + + length = strlen(treeSym); + if (length >= MAX_TREE_DEPTH) return; + + if (glink->pgroupData->treeSym && + (length+1) > (int)strlen(glink->pgroupData->treeSym) ) { + free(glink->pgroupData->treeSym); + glink->pgroupData->treeSym = 0 ; + } + + if (!glink->pgroupData->treeSym) + glink->pgroupData->treeSym = (char *)calloc(1,length+1); + + /* find next view sibling */ + pt = sllNext(glink); + while (pt){ + if (command == NOCHANGE){ + if (((GLINK *)pt)->viewCount>0) break; + } else { + if (viewFilter((GCLINK *)pt)) break; + } + pt = sllNext(pt); + } + + if (length){ + if (pt) treeSym[length-1] = symMiddle; + else treeSym[length-1] = symEnd; + treeSym[length] = symNull; + strcpy(glink->pgroupData->treeSym,treeSym); + } + + if ( command == COLLAPSE) return; + + if ( command == NOCHANGE && glink->viewCount == 1) return; + + subcommand = command; + if ( command == EXPANDCOLLAPSE1){ + if ( oldViewCount > 1) return; + subcommand=COLLAPSE; + } + + if (length){ + if (pt) treeSym[length-1] = symContinue; + else treeSym[length-1]=symBlank; + } + + pt = sllFirst(&(glink->subGroupList)); + if (!pt) return; + + if (glink->viewCount) treeSym[length]=symBlank; + + while (pt){ + treeView((GLINK *)pt, subcommand, treeSym, viewFilter); + if ( command != NOCHANGE) glink->viewCount += ((GLINK *)pt)->viewCount; + pt = sllNext(pt); + } + + treeSym[length]=symNull; + return; +} + +/*************************************************** + Return next treeWindow item open for view +****************************************************/ +GCLINK *alViewNextTreeW(GLINK *glink,int *plinkType) +{ + GLINK *glinkTemp; + SNODE *pt; + + *plinkType = GROUP; + + /* try child */ + if (glink->viewCount >1){ + pt = sllFirst(&glink->subGroupList); + while (pt){ + if (((GLINK *)pt)->viewCount) break; + pt = sllNext(pt); + } + return((GCLINK *)pt); + } + + /* try following siblings */ + pt = sllNext(glink); + while (pt){ + if (((GLINK *)pt)->viewCount) break; + pt = sllNext(pt); + } + if (pt) return((GCLINK *)pt); + + /* try parent siblings */ + glinkTemp = glink->parent; + while (glinkTemp){ + pt = sllNext(glinkTemp); + while (pt){ + if (((GLINK *)pt)->viewCount) break; + pt = sllNext(pt); + } + if (pt) return((GCLINK *)pt); + + glinkTemp = glinkTemp->parent; + } + return(NULL); +} + +/*************************************************** + Return next groupWindow item open for view +****************************************************/ +GCLINK *alViewNextGroupW(GCLINK *link,int *plinkType) +{ + SNODE *pt; + GLINK *parent; + + pt = sllNext((SNODE *)link); + while(pt){ + if (((GCLINK *)pt)->viewCount) break; + pt = sllNext(pt); + } + if (!pt && *plinkType == GROUP){ + parent = link->parent; + pt = sllFirst(&(parent->chanList)); + *plinkType = CHANNEL; + while(pt){ + if (((GCLINK *)pt)->viewCount) break; + pt = sllNext(pt); + } + } + return((GCLINK *)pt); +} + +/*************************************************** + Return nth treeWindow item open for view +****************************************************/ +GCLINK *alViewNthTreeW(GLINK *glinkStart,int *plinkType,int n) +{ + GLINK *glink; + int count; + SNODE *pt; + + *plinkType = GROUP; + + if (!glinkStart) return(NULL); + glink = glinkStart; + if (!glink->viewCount) return(0); + if (n > glink->viewCount) return(0); + count = 0; + + while (countviewCount > n ){ + if (glink->viewCount) count++; + glink = (GLINK *)sllFirst(&glink->subGroupList); + } + else { + count += glink->viewCount; + pt = sllNext(glink); + while (!pt){ + glink = glink->parent; + if (!glink) break; + pt = sllNext(glink); + } + glink = (GLINK *)pt; + if (!glink) return(NULL); + } + } + if (count != n) return(NULL); + return((GCLINK *)glink); +} + +/*************************************************** + Return nth groupWindow item open for view +****************************************************/ +GCLINK *alViewNthGroupW(GLINK *link,int *plinkType,int n) +{ + + SNODE *pt; + int count= 0; + + *plinkType = 0; + + if (!link) return(0); + pt = sllFirst(&link->subGroupList); + while ( pt){ + if (count == n && ((GCLINK *)pt)->viewCount) break; + if (((GCLINK *)pt)->viewCount) count++; + pt = sllNext(pt); + } + if (pt) { + *plinkType = GROUP; + return((GCLINK *)pt); + } + pt = sllFirst(&(link->chanList)); + while (pt){ + if (count == n && ((GCLINK *)pt)->viewCount) break; + if (((GCLINK *)pt)->viewCount) count++; + pt = sllNext(pt); + } + if (pt) { + *plinkType = CHANNEL; + } + return((GCLINK *)pt); +} + +/*************************************************** + Get groupWindow max sevr in range from glinkstart + to Nth item following linkstart +****************************************************/ +int alViewMaxSevrNGroupW(GCLINK *linkStart,int n) +{ + GLINK *glink; + GLINK *parent; + CLINK *clink=0; + int count= 0; + int sevr = 0; + int linkType; + + if (n <= 0 || !linkStart) return(0); + + /* determine linkType of linkStart */ + parent = linkStart->parent; + glink = (GLINK *)sllFirst(&parent->subGroupList); + while ( glink){ + if ((GCLINK *)glink == linkStart ) break; + glink = (GLINK *)sllNext(glink); + } + if (glink) { + linkType = GROUP; + } else { + linkType = CHANNEL; + clink = (CLINK *)sllFirst(&(parent->chanList)); + while (clink){ + if ((GCLINK *)clink == linkStart) break; + clink = (CLINK *)sllNext(clink); + } + } + + /* determine maximum severity below linkStart */ + if (linkType == GROUP ){ + while ( glink){ + if (count == n) break; + if (glink->viewCount) { + sevr = Mmax(sevr,glink->pgroupData->curSevr); + if (sevr >= ALH_ALARM_NSEV-1) break; + count++; + } + glink = (GLINK *)sllNext(glink); + } + if (sevr >= ALH_ALARM_NSEV-1) return(sevr); + if (glink) { + return(sevr); + } + clink = (CLINK *)sllFirst(&(parent->chanList)); + } + while (clink){ + if (count == n) break; + if (clink->viewCount) { + sevr = Mmax(sevr,clink->pchanData->curSevr); + count++; + } + if (sevr >= ALH_ALARM_NSEV-1) break; + clink = (CLINK *)sllNext(clink); + } + return(sevr); +} + +/*************************************************** + Get treeWindow max sevr in range from glinkstart + to nth item following glinkstart +****************************************************/ +int alViewMaxSevrNTreeW(GLINK *glinkStart,int n) +{ + GLINK *glink; + CLINK *clink=0; + SNODE *pt; + int sevr=0; + int count=0; + + if (n <= 0 ) return(0); + if (!glinkStart) return(-1); + glink = glinkStart; + if (!glink->viewCount) return(-1); + + while (countviewCount > n ){ + /* max severity of channels within group */ + clink = (CLINK *)sllFirst(&(glink->chanList)); + while (clink){ + sevr = Mmax(sevr,clink->pchanData->curSevr); + if (sevr >= ALH_ALARM_NSEV-1) break; + clink = (CLINK *)sllNext(clink); + } + if (sevr >= ALH_ALARM_NSEV-1) break; + count++; + glink = (GLINK *)sllFirst(&glink->subGroupList); + } + else { + if (glink->viewCount) + sevr = Mmax(sevr,glink->pgroupData->curSevr); + if (sevr >= ALH_ALARM_NSEV-1) break; + count += glink->viewCount; + pt = sllNext(glink); + while (!pt){ + glink = glink->parent; + if (!glink) return(sevr); + pt = sllNext(glink); + } + glink = (GLINK *)pt; + } + } + return(sevr); +} + diff --git a/alarm.c b/alarm.c new file mode 100644 index 0000000..483e7fb --- /dev/null +++ b/alarm.c @@ -0,0 +1,46 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alarm.c */ + +/************************DESCRIPTION*********************************** + Initial alhAlarm global variables +**********************************************************************/ + +#include "alh.h" +#include "ax.h" +#include "alarmString.h" + +const char * alhAlarmSeverityString[ALH_ALARM_NSEV ]; +const char * alhAlarmStatusString[ALH_ALARM_NSTATUS]; +const char * alhErrorSeverityString[] = { "ERROR" }; +const char * alhErrorStatusString[] = { "NOT_CONNECTED","NO_READ_ACCESS","NO_WRITE_ACCESS" }; + +void alhAlarmStringInit() +{ + int i; + + for (i=0;i +#include + +#include "alh.h" +#include "epicsVersion.h" +#include "version.h" +#include "fallback.h" +#include "sllLib.h" +#include "axArea.h" +#include "ax.h" + +/* global variables */ +const char *executionModeString[] = {"Local","Global"}; +const char *ackTransientsString[] = {"ackT","noackT"}; +Widget productDescriptionShell; +XtAppContext appContext; +Widget topLevelShell; +Display *display; + + + +int DEBUG = 0; +SLIST *areaList; +char alhVersionString[100]; +XFontStruct *font_info; + +/****************************************************** + main +******************************************************/ + +int main(int argc,char *argv[]) +{ + /* OS specific initialization */ +#ifdef WIN32 + HCLXmInit(); +#endif +#ifdef HP_UX + _main(); +#endif + + /* Xt initialize the application */ + topLevelShell = XtAppInitialize(&appContext, "Alarm", NULL, 0, &argc, argv, + fallbackResources, NULL, 0); + + /* check display */ + display = XtDisplay(topLevelShell); + if (display == NULL) { + XtWarning("cannot open display"); + exit(-1); + } + + XtAppSetWarningMsgHandler(appContext, + (XtErrorMsgHandler)trapExtraneousWarningsHandler); + + /* load fixed font */ + font_info = XLoadQueryFont(display,"fixed"); + + /* initialize alh status and severity values */ + alhAlarmStringInit(); + + sprintf(alhVersionString,"ALH Version %d.%d.%d (%s)", + ALH_VERSION,ALH_REVISION,ALH_MODIFICATION,EPICS_VERSION_STRING); + + /* setup area and configuration */ + fileSetupInit(topLevelShell,argc,argv); + + /* display alh credits window */ +#if IWantGreetings + productDescriptionShell = createAndPopupProductDescriptionShell( appContext, + topLevelShell, + " ALH ", NULL, ALH_pixmap, + "\nAlarm Handler\n Alarm Configuration Tool\n",NULL, + ALH_CREDITS_STRING , + alhVersionString, + NULL, -1,-1,3); +#else + productDescriptionShell = 0; +#endif + + /* Start main loop */ + XtAppMainLoop(appContext); + return 0; +} + diff --git a/alh.h b/alh.h new file mode 100644 index 0000000..6af1732 --- /dev/null +++ b/alh.h @@ -0,0 +1,274 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alh.h */ + +/************************DESCRIPTION*********************************** + Alh header file of #defines and structure definitions +**********************************************************************/ + +#ifndef INCalhh +#define INCalhh + +#include + +#include +#include + +#include "alarm.h" +#include "cadef.h" + +#if (!defined(WIN32) && !defined(__APPLE__)) +#define HAVE_SYSV_IPC +#endif + +#ifdef EXCEED +/* WIN32 differences */ +#ifdef WIN32 +/* Hummingbird extra functions including lprintf + * Needs to be included after Intrinsic.h for Exceed 5 + * (Intrinsic.h is included in xtParams.h) */ +# include +/* Needed for access */ +# include +/* This is done in Exceed 6 but not in Exceed 5 + * Need it to define printf as lprintf for Windows + * (as opposed to Console) apps */ +# ifdef _WINDOWS +# ifndef printf +# define printf lprintf +# endif +# endif +#endif /* #ifdef WIN32 */ +#endif + +#include "sllLib.h" +#include "dbDefs.h" + +#ifndef FLDNAME_SZ +#define FLDNAME_SZ 4 /*Field Name Size*/ +#endif + +/* ------- Definitions for channels in error state ----- */ +/* ALARM_NSEV and ALARM_NSTATUS defined in epics/base alarm.h */ + +#define ERROR_STATE ALARM_NSEV +#define ALH_ALARM_NSEV ALARM_NSEV + 1 + +#define NOT_CONNECTED ALARM_NSTATUS +#define NO_READ_ACCESS ALARM_NSTATUS +1 +#define NO_WRITE_ACCESS ALARM_NSTATUS +2 +#define ALH_ALARM_NSTATUS ALARM_NSTATUS + 3 +/* ----------------------------------------------------- */ + +/* size of name */ +#define NAMEDEFAULT_SIZE 150 /* file name size */ +#define OPMODMESSAGE_SIZE 130 /* opmod log line size */ +#define PVNAME_SIZE PVNAME_STRINGSZ+FLDNAME_SZ /* PV name size from dbDefs.h */ + + +/* parameters for mask selection */ +#define ALARM_NMASK 5 +#define ALARMCANCEL 0 +#define ALARMDISABLE 1 +#define ALARMACK 2 +#define ALARMACKT 3 +#define ALARMLOG 4 + +#define MASK_OFF 0 +#define MASK_ON 1 +#define MASK_RESET 2 + +/* parameters for file specifications */ +#define CONFIG_FILE 0 +#define ALARM_FILE 1 +#define OPMOD_FILE 2 +#define N_LOG_FILES 3 +#define INITIAL_FILE_LENGTH 204800 + +/* parameters for fileSetupCallback */ +#define FILE_CONFIG 0 +#define FILE_CONFIG_INSERT 2 +#define FILE_SAVE 3 +#define FILE_SAVEAS 4 +#define FILE_SAVEAS_OK 5 +#define FILE_ALARMLOG 6 +#define FILE_OPMOD 7 +#define FILE_PRINT 8 + +#define MAX_TREE_DEPTH 50 + +/* define parameters for menu callbacks */ +#define MENU_EDIT_UNDO_PASTE_NOSELECT 10700 +#define MENU_EDIT_UNDO_PASTE 10701 +#define MENU_EDIT_UNDO_CUT 10702 +#define MENU_EDIT_UNDO_CUT_NOSELECT 10703 +#define MENU_EDIT_UNDO_UPDATE_CLIPBOARD 10704 +#define MENU_EDIT_UNDO_PROPERTIES 10705 +#define MENU_EDIT_UNDO_CLEAR 10706 + +#ifdef Mmax /* just in case--we don't know, but these are commonly set */ +#undef Mmax /* by arbitrary unix systems. Also, we cast to int! */ +#endif +/* redefine "max" and "min" macros to take into account "unsigned" values */ +#define Mmax(a,b) ((int)(a)>(int)(b)?(int)(a):(int)(b)) +#define Mmin(a,b) ((int)(a)<(int)(b)?(int)(a):(int)(b)) + +#define AUTOMATIC 0 +#define OPERATOR 1 + +#define GROUP 1 +#define CHANNEL 2 + +#define MAX_STRING_LENGTH 500 + +/* define commands for modifying the current view */ +#define EXPAND 0 +#define EXPANDCOLLAPSE1 1 +#define COLLAPSE 2 +#define NOCHANGE 3 + +#define ACT 0 +#define ALH 1 + +#define CA_CONNECT_NO 0 +#define CA_CONNECT_YES 1 + +#define CONFIG_PATTERN "*.alhConfig" +#define OPMOD_PATTERN "*.alhOpmod" +#define ALARMLOG_PATTERN "*.alhAlarm" +#define TREEREPORT_PATTERN "*.alhReport" + +typedef struct { + char *label; + void (*callback)(Widget, XtPointer, XtPointer); + XtPointer data; +} ActionAreaItem; + +#define TIGHTNESS 30 + +/* ------- start of defines for global variables */ +extern char *programName; +extern SLIST *areaList; +extern Display *display; +extern XtAppContext appContext; +extern Widget topLevelShell; +extern Widget productDescriptionShell; +extern Pixmap ALH_pixmap; +extern int programId; + +struct heartbeatPV { + char *name; + chid chid; + float caputRateInSeconds; + short caputValue; + XtIntervalId timerId; +}; + +struct setup { + char configFile[NAMEDEFAULT_SIZE]; /* config file name */ + char logFile[NAMEDEFAULT_SIZE]; /* alarm log file name */ + char opModFile[NAMEDEFAULT_SIZE]; /* opMod log file name */ + char saveFile[NAMEDEFAULT_SIZE]; /* save config file name */ + short silenceForever; /* 1 - beepoff forever is true */ + short silenceOneHour; /* 1 - beepoff one hour is true */ + short silenceCurrent; /* 1 - current beep on 0 - off */ + short beepSevr; /* 1,2,3,4,5 */ + short highestSevr; /* system highest sevr */ + short highestUnackSevr; /* system highest unack sevr */ + short highestUnackBeepSevr; /* system highest unack sevr >= beep sevr */ + short newUnackBeepSevr; /* new unack sevr after beep sevr tests */ + char *configDir; /* config files directory */ + char *logDir; /* log files directory */ +}; + +struct mainGroup { + struct groupLink *p1stgroup; /* main group pointer */ + int modified; + void *area; + struct heartbeatPV heartbeatPV; /* heartbeat PV info */ +}; + +extern struct setup psetup; + +/* log message types */ +#define REGULAR_RECORD 1 /* usual alLog mess. */ +#define CONNECT_ALARM 2 /* specific alLog format about connection lost */ +#define STOP_LOGGING_ALARM 3 /* specific alLog format about stopping loging */ +#define MESSAGE_QUEUE_ALARM 4 /* specific alLog format about MQ problems */ +#define ACK_CHANNEL 5 /* op_mod action which will be saving in DB */ +#define ACK_GROUP 6 /* Don't used now */ +#define CHANGE_MASK 7 /* op_mod action which will be saving in DB */ +#define CHANGE_MASK_GROUP 8 /* op_mod action which will be saving in DB */ +#define FORCE_MASK 9 /* op_mod action which will be saving in DB */ +#define FORCE_MASK_GROUP 10 /* op_mod action which will be saving in DB */ +#define ALARM_LOG_DB 1 /* We are write to ALARM_LOG database */ +#define OP_MOD_DB 2 /* We are write to OP_MOD database */ + + + +#endif /* INCalhh */ + +/************************************************************************************* + +-------------------------------------------------------------------------------------- + -------------- ALH File Information ---------------- +-------------------------------------------------------------------------------------- + + + NOTE: See h files for information on specific routines + + + ALH.bit ALH icon definition + + acknowledge.c Alarm acknowledgement routines + alCA.c Config routines for communicating with Channel Access + alConfig.c Routines related to read/write of alarm configuration + alDebug.c Config debugging routines + alInitialize.c Config routines for Alarm configuration initialization + alLib.c Config routines to create, delete and modify groups/channels + alLog.c Config routines for logging of alarms and messages + alView.c Config routines for modifying the configuration view + alh.c ALH Main program + awAct.c Interface routines for ACT menu, subW line, and callbacks + awAlh.c Interface routines for ALH menu, subW line, and callbacks + awView.c X routines for modifying and displaying the config view + axArea.c X routines for setup of area and area Main Window + axRunW.c X routines related to the iconlike runtime window + axSubW.c X routines for tree and groupContents subWindows + current.c Routines for current alarm history (last 10 alarms) + dialog.c Routines for creating dialogs + file.c Routines for file handling and alh exit + force.c Routines for force group/channel masks and forcePV changes + guidance.c Routines for displaying group or channel guidance + help.c Routines for display of ALH help text + line.c Routines for alloc, init, and update of a subWindow line + mask.c Routines for modifying group/channel masks + process.c Routines for spawning a related process + scroll.c Routines for viewing files using a scrolled window + showmask.c Routines for showing group/channel masks summary + sllLib.c Routines for single link list operations + testalarm.c Routines for generation of a testalarm dialog + + alLib.h Defs of MASK,GLINK,CLINK,GCLINK,groupData,chanData,gcData + alarmString.h String values for alarm status and severity + alh.h #defines, masksdata, setup,mainGroup ... + axArea.h A Defs of ALINK, MenuItem + axSubW.h Defs of subWindow structure + clipboardOps.h #defines + fallback.h Def of X fallback resource values + line.h Defs of anyLine,WLINE + sllLib.h Defs of SNODE,SLIST, sllFirst,sllInit,sllLast,sllNext + +**************************************************************************************/ diff --git a/alh.ico b/alh.ico new file mode 100644 index 0000000..3ef307f Binary files /dev/null and b/alh.ico differ diff --git a/alh.notes b/alh.notes new file mode 100644 index 0000000..47773aa --- /dev/null +++ b/alh.notes @@ -0,0 +1,563 @@ +6/17/96 changes + Fixed maximum length of filename on include line. + + Added global alarm acknowledgement. + + +Thu Aug 22 14:59:41 CDT 1996 + + Bug fix: + "Save as" now writes out ALARMCOUNTFILTER data + +Thu Jan 9 08:36:21 CST 1997 + + In this new alh version, the alarm log file has been changed to a circular log + file with maximum records in the circular file defaulting to 2000. This means + that after 2000 records exist in the alarm log file, the oldest alarm records + will be overwritten when new alarms occur, thus keeping the file size a constant + 2000 records. The maximum number of records can be changed using a command line + option m, e.g. "alh -m 5000" will make the alarm log file a circular file with a + maximum of 5000 records. The command "alh -m 0" can be used to allow the alarm + log file to have an infinite number of records. + +Thu Jan 16 10:35:16 CST 1997 + + Bug fix to ALARMCOUNTFILTER + +Fri Feb 28 17:26:13 CST 1997 + + Fixed INCLUDE file bug which caused counts and alarms to be incorrect. + + +Mon Mar 31 10:41:19 CST 1997 + + Bug fix to SEVRCOMMAND for UP_ANY and DOWN_ANY. + Bug fix to ALARMCOUNTFILTER. + +Fri Sep 12 16:25:02 CDT 1997 + + Modified Help menu items. + Removed libUnix dependancy (product description shell) + Fixed calloc for SEVRCOMMAND string. + Fixed calloc for treeSym. + Bug fix for $BEEPSEVERITY line. + Alarm Configuration Tool (alh -c ) changes + Removed Undo from Edit menu - more confusing than helpful. + Many changes to get properties window working. + Changes to get cut/paste working. + Bug fixes for Save and SaveAs. + Bug fixes for tree and group window views. + +Mon Oct 27 12:28:36 CST 1997 + + Write of sevr to sevrPVs now done even if acknowledgement not + necessary and now write is done only when sevr has changed. + + +May - June 1998 + Changes made to allow alh to build using Exceed on WIN95/NT + Added new icon + Removed references to getopt + Created Makefile.Host and modified Makefile + +date: 1997/09/12 21:23:53 + Bug fix for beep severity line placement. + +date: 1998/06/01 18:33:21 + Modified the icon. + +date: 1998/06/02 19:40:43; author: evans; state: Exp; lines: +2 -1 + Changed from using Fgmgr to using X to manage events and file + descriptors. (Fdmgr didn't work on WIN32.) Uses XtAppMainLoop, + XtAppAddInput, and XtAppAddTimeOut instead of Fdmgr routines. + Updating areas is now in alCaUpdate, which is called every caDelay ms + (currently 100 ms). Added a general error message routine (errMsg) + and an exception handler (alCAException). Is working on Solaris and + WIN32. + +date: 1998/06/04 17:31:58; + Changed system("command &") to _spawnl("command") for WIN32 in + processSpawn_callback. Added test.win32.alhConfig. + +date: 1998/06/09 17:10:48; author: evans; state: Exp; lines: +5 -1 + Fixed a typo in the exception handler. + +Mon Jun 22 12:50:36 CDT 1998 + Bug fixes for command line option handling. + Modified debug options in Makefile.Host + +Mon Jun 22 13:34:09 CDT 1998 + Merged the new alh-options created at DESY MKS group: + + -D Disable Writing --- allows running alh without creating/modifying + alarmLog and alarmOpMod files. + -S Passive Mode --- means that operator can't acknowledge alarms + and can't save alarmLog and alarmOpMod files. + -T AlarmLogDated --- 1) alarmLog files will have "date" extensions + like YYYY-MM-DD, and automatical switching + this files in midnight. + + 2) We add FSbox for search LogFiles in + View->"Alarm Log File Window" and + + 3) We add search button for finding string at LogFile. + + 4) We add "Find from to with " + widget, which allow search from + all AlLog-files at some directory + + -P Printing --- simultaneously printing Alarm to TCP printer + (socket connection and so on). Now we print it + asynchronous, so we add additional task "alh_printer" + and modificate Makefile.Unix. + +Wed Jul 1 15:02:21 CDT 1998 + Bug fix for STATCOMMAND. + +date: 1998/07/07 20:49:01; author: jba; state: Exp; lines: +9 -2 + Removed unused variable timeout. + Added alh versioning file version.h. + +date: 1998/07/16 17:45:17; author: jba; state: Exp; lines: +2 -1 + Moved productDescriptionShell code from libUnix to alh. (libUnix removed) + Changed some XmStringCreateSimple to XmStringCreateLtoR in dialog.c. + Allowed alh to startup with no filename on command line. + +date: 1998/07/23 18:22:34; author: jba; state: Exp; lines: +7 -6 + Log the connection and access rights changes to alarm log file + Exit routine changes for alarm configuration tool. + +Wed Jul 29 12:27:09 CDT 1998 + Added "Unacknowledged Alarms Only" display filter. + +Mon Aug 3 13:04:40 CDT 1998 + Increased config file max line size to 500 chars. + +Wed Aug 5 13:10:12 CDT 1998 + Added silenceOneHour button. + Moved silenceForever button to Setup menu. + Added logging for operator silence changes. + Reading config file modified to compare whole word of command + (GROUP,CHANNEL,$GUIDANCE,...)instead of first letter. + GUIDANCE modified to display urls. (on netscape browser). + The alhConfig file specification is now either URL guidance - + $GUIDANCE http://www.aps.anl.gov/asd/controls + or text guidance - + $GUIDANCE + This is the first line of text guidance. + This is the second line of text guidance. + $END + +Fri Aug 7 17:30:14 CDT 1998 + Alh now quits when invalid config file is specified on command line. + +Thu Sep 3 14:11:17 CDT 1998 + Added new version of browser.c with WIN32 support. + Removed unused variables from file.c. + Made changes for WIN32 build (using Exceed5) + Added url help. + Initial version is 1.1.1, added Albert to credits + +Wed Sep 9 11:06:51 CDT 1998 + Merged the new alh code changes from CEBAF: + Removed the old -DACCESS_SECURITY tests (pre baseR3.11). + +Thu Jan 19 14:14:01 CST 1999 + Start of code cleanup. No functional changes. Modified comments, removed + unused code, used c beautifier, etc. + +Thu Jan 28 16:57:39 CST 1999 + Added silenceForever command line option. + Modified silenceForever menu item to actually silence forever instead + of silencing only for current file. + Modified the url help location. + +Thu Mar 11 10:12:06 CST 1999 + Added the following alh modifications which were created at DESY MKS group. + + New alh-options: + + -D Disable Writing --- allows work with alh without possibility + create/modify alarmLog and alarmOpMod files. + -S Passive Mode --- means that operator can't acknowledge alarms + and can't save alarmLog and alarmOpMod files. + -T AlarmLogDated --- 1) alarmLog and OpMod files will have "date" extensions + like YYYY-MM-DD, and automatical switching + this files in midnight. + + 2) We add FSbox for search LogFiles in + View->"Browser for Alarm Log" and + + 3) We add search button for finding string at LogFile. + + 4) We add "Find from to with " + widget, which allow search from + all AlLog-files at some directory + + -P Printing --- simultaneously printing Alarm to TCP printer + (socket connection and so on). Now we print it + asynchronous, so we add additional task "alh_printer" + and modificate Makefile.Unix. + + -L locking --- allow multiple work with the same config files, + only one process is real master and write to alhLog + other is slave and they wait until master will not killed + + -0 Database(Oracle) --- simultaneously runtime add Alarm to Database. + it works asynchronous, so we add additional task "alh_DB" + + -B - message broadcasting -- allow send messages between operators work with the + same config file. Most important case: "REBOOT MESSAGE": + allow don't save alarm during reboot time. + (NOT IMPLEMENTED YET ;) ) + +Mon Mar 15 08:57:01 CST 1999 + ANSI c changes to eliminate warning messages on Linux build. + +Tue May 18 10:24:41 CDT 1999 + Bug fix for reversed parameters in alLogChanChangeMasks. + Added Silence Forever status to message area. + +Fri May 28 15:08:18 CDT 1999 + Bug fix for forcePV. Removed alInitialize.c. + +Wed Jun 2 13:16:33 CDT 1999 + Bug fix for area reinitialization after a new config file opened + which sometimes caused a core dump. + Removed alAllocGroup/alAllocChan (alCreateGroup/alCreateChannel used). + Current Alarm History data no longer global, now part of area structure. + +Mon Jun 7 09:20:02 CDT 1999 + Modified definition of netscape path. + +date: 1999/07/08 14:35:02; author: lange; + += CMLOG support + +Mon Jun 21 15:15:03 CDT 1999 + Start cleanup of axRunW.c file. + +Tue Jun 22 11:12:51 CDT 1999 + Some cleanup of line.h and line.c files. + +Wed Jul 14 16:24:06 CDT 1999 + Updates to handle global acks and ackt fields and related changes. + Created version 1.2.1 + +date:1999/07/21 23:02:10 + Cdev and Exceed changes. + Bug fixes for command line options. + Corrected cmlog function names. + +date: 1999/07/22 21:30:42 + Fixed usage text. + Two CMLOG fixes + Fixed the context setting for value. + Force new alarm processing when channel is initally disconnected. + +date: 1999/07/23 14:38:52; author: lange; + += -filter, -mainwindow; fixed cmdline option error output + +date: 1999/07/26 15:32:25; author: lange; + Small CMLOG related changes + Changed CMLOG browser call to allow args + GetChannelLine() bugfix + Update current mask string + +date: 1999/07/28 21:26:19; author: jba; + Message area text changes. + Don't log the initial connection. + +date: 1999/08/13 19:43:46; author: lange; cmlogrc.ALH + changed host tag, added more tags + +date: 1998/06/01 18:33:24; author: evans; alh.ico + Modified the icon. + +Wed Oct 6 16:13:50 CDT 1999 + Process forcePV ca value event only if value has changed. + +Thu Oct 14 10:11:23 CDT 1999 + Fixed alarm channel count for INCLUDE files. + Fix for ca put of ACKT values when config file is read. + Fix for alarm sevr of initially canceled and disabled channels. + Created version 1.2.2 + +Tue Oct 26 09:14:53 CDT 1999 + Run window now displays color of highest unack alarm. + Process initial alarm event for ALARMCOUNTFILTER channels. + +Tue Nov 2 14:10:45 CST 1999 + Don't do caput for acknowledgment if channel is not connected. + Wait for a 1 second period with no connections before writing + config file ackt settings. + +Fri Nov 12 16:27:37 CST 1999 + Don't set unack global sevr from alarm events if curMask.Ack==true + Created version 1.2.3 + +1999/12/08 19:41:11; author: jba + Changed win32 compile option to start with slash for consistancy. + Initialized parent_link to null. + +Mon Apr 24 09:40:43 CDT 2000 - V1.2.4 + Simplified alHighestSystemSeverity calculation. + Added new alarm event error checking. + Created version 1.2.4 + +Wed Aug 9 09:16:57 CDT 2000 - V1.2.5 + Fixed some memory leaks in scroll.c and dialog.c and file.c. + Removed change to group curSevr in alView.c. Added CMLOG_BIN + definition and added -R ld option for cmlog in Makefile.Host. + Added acks and ackt fields to countFilter structure in alLib.h. + Modified the handling of new events when a count Filter exists, + see comment table in alLib.c (near line 630 ). + Created version 1.2.5 + +2000/08/15 17:00:20; author: lange + Added startup code for HP C++-Linker + +Tue Sep 26 10:30:55 CDT 2000 + Added audio for WIN32 and fixed some memory leaks. + +Thu Oct 5 14:49:17 CDT 2000 - V1.2.6 + Added audio for solaris. + Created version 1.2.6 + +2000/10/09 21:06:33; author: jba + Made changes for building with solaris 6. + +Tue Oct 17 14:08:17 CDT 2000 - V1.2.7 + Change to build with baseR3.14. + Created version 1.2.7 + +Tue Oct 24 16:01:07 CDT 2000 - V1.2.8 + More changes to build with baseR3.14. + Created version 1.2.8 + +Tue Feb 13 09:24:37 CST 2001 - V1.2.9 + Fixed bug in new alarm event filtering. + Removed update of current alarm history when window not displayed. + +Tue Feb 20 09:42:46 CST 2001 - V1.2.9 + Reinstated update of current alarm history when window not displayed. + Created version 1.2.9 + +2001/10/09 18:07:47; author: evans + Fixed code to not use ALH_Pixmap as XmNiconPixmap for WIN32, since Exceed + trashes it. + +2002/01/17 22:00:04; author: jba + Changed HOST_ARCH to OS_CLASS in Makefile.Host + +2002/02/04 19:56:15; author: jba + Set ellNext parm cast to ELLNODE* to avoid compiler warnings. + +2002/05/17 20:51:09; author: jba + Added const to avoid compiler warnings. + +Tue Jul 23 16:21:37 CDT 2002 + Added license information to source files. Added LICENSE file. + Created version 1.2.10 + +Wed Sep 11 10:20:10 CDT 2002 + Added missing notes to alh.notes file. + Initialized FILE fl and fo to zero to avoid compiler warnings. + +Mon Jan 20 09:18:18 CST 2003 + Add ability to set and change beep severity for channels and groups. + +Tue Jan 21 15:53:59 CST 2003 + Simplify Beep Severity dialog: set value immediately and remove Apply and Ok. + Add ability to set group/channel ack/noAck masks to noAck for one hour. + Add ability to disable a group/channel forcePV. + +Mon Jan 27 13:52:29 CST 2003 + More changes for noAck for one hour timer. + Allow "NE" for forcePV reset value ( NE forcePV force value). + +Tue Feb 11 15:28:34 CST 2003 ALH_1_2_11Beta1 + More changes for noAck for one hour timer. New Action menu item + "NoAck for One Hour". Channel have Ack mask set to reset value + after one hour. Ability to permanently noAck/Ack a group or + channel. Groups or channels with 1 hour timer will display an + 'H' in Ack mask field. A new no-Ack timer will cancel existing + timers in subgroups and channels. When timer expires it will + not reset any subgroups or channels that have an existing (i.e. + more recent) timer. + + The text "ALH" has been added to the old Setup Beep Severity + menu item and to the Beep Severity line in the main window message + area to show that it is not a group or channel beep severity. + + Now when a channel is enabled after being disabled and it is not + in an alarm state but does have unacknowledged transient alarms, an + automatic acknowlegment is sent to the channel and the auto acknowledge- + ment is logged in the opMod file. + +Fri Feb 14 16:24:03 CST 2003 ALH_1_2_11Beta2 + Added H indicator in mask for noAck 1hr timer + Added a config file heartbeatPV. + +Thu Feb 27 10:59:56 CST 200 ALH_1_2_11Beta3 + ForcePV variables removed grom gcData and forcePV structure created. + Added NE as a valid value for forcePV resetValue. + Added CALC facility to forcePV. This allows algebraic, relational, and + logical operations on up to 6 pvs. The result of the operations is then + compared to the forcePV forceValue and resetValue to determine whether + to set group/channel masks to the forceMask or resetMask. + +Fri Feb 28 16:38:19 CST 2003 ALH_1_2_11Beta4 + Changed opMod file output. Now contains top group name followed by + group or channel name each followed by a colon or just a colon if + the name is not available. + +Mon Mar 3 09:24:38 CST 2003 ALH_1_2_11Beta5 + Moved channel beepSevr modified indicators to preceed possible return. + Added code for display of highest existing beepSevr in sub groups and channels. + Modified alarm log file output. Now calculate alarmLogFileStringLength. + Changed fopen of alarm log file from r+ to w+(truncate or create). + Modified forcePV opMod log messages text. + +Wed Sep ? 12:55:31 ALH_1_2_12 + Created tag ALH_1_2_12 for a requested distribution tar file. + +Wed Oct 8 16:01:03 CDT 2003 ALH_1_2_13 + Code changed to reduce warning messages. + Write "N/A" to cmlog when blink string is missing. + Fixes made to Force Mask popup. + Removed old sccs id variable. + +Wed Feb 25 22:28:56 CDT 2004 ALH_1_2_14 + Change conditional from WIN32 to HAVE_SYSV_IPC. Add appropriate conditional + to alh.h to define HAVE_SYSV_IPC as appropriate. Ensure that alh.h is + included before conditionals depending on HAVE_SYSV_IPC. + +Tue Jun 1 15:41:38 CDT 2004 ALH_1_2_15 + Added -desc_field option. - Albert Kagarmanov + Added acknowledge PV support - Albert Kagarmanov + Portablility change for darwin-ppc - Eric Norum + +Fri Jul 16 16:22:32 CDT 2004 ALH_1_2_16 + Added comments and void return value for getDescriptionRecord. + Saved ca alarm event data and added a ca reconnection event (for R3.14.6). + +Thu Jul 22 11:02:33 CDT 2004 ALH_1_2_17 + Removed menu tearoff feature. Tornoff menus cannot be closed. + +Mon Aug 2 09:24:36 CDT 2004 ALH_1_2_18 + Modified save of ca alarm event data to save only at a disconnect event. + +Tue Aug 10 10:48:18 CDT 2004 ALH_1_2_19beta1 + Skip restoring saved alarm data at initial connection. + Popup error msg for unconnected SEVRPV, FORCEPV, ACKPV, HEARTBEATPV + Popup error msg when no read access for FORCEPV + Popup error msg when no write access for SEVRPV, ACKPV, HEARTBEATPV + Popup error msg when no read or write access for alarm channels + Added ca clear channel for Acknowledge PV. + Popup error msg for invalid SEVRPV, FORCEPV, ACKPV, HEARTBEATPV input + +Fri Oct 29 14:54:00 CDT 2004 ALH_1_2_19beta2 + Set main window background color pink if Silence For One Hour is active. + +Tue Apr 5 10:06:27 CDT 2005 + Added "ALH" to popup dialogs and added timestamp to popup error dialog. + +Tue Jun 21 13:23:04 CDT 2005 ALH_1_2_20 + Silence One Hour: + Set color of newly created row widgets to color of parent widget. + Change color of ALL widget children except ack button, sevr indicator, + and name push button. + Write errMsg text to opMod log file when errors occur. + Remove extra carriage returns in opMod log file. + Remove group and channel data from opMod log message if they do not exist. + Print "Setup Config File" to opMod log before config file error messages. + Open file for scroll window reading as r. Removed comments. Cleaned code. + Set cursor position to last line written, even in circular files. + Create new dialog when a dialog is requested. Destroy dialog when closed. + +Mon Dec 5 10:23:24 CST 2005 + Added alh_printer libraries socket & nsl for R3.14.8 build to Makefile.Host. + + +Fri Feb 23 09:31:05 CST 2007 ALH_1_2_21 + Fixed core dump after pushing a Silence button on linux. (Initialized + numChildren before getting XmNnumChildren.) + Portability changes for darwin. + Moved code for alCaCancel. + Updated to R3.14 Makefiles. + +Tue Jun 26 10:27:36 CDT 2007 ALH_1_2_22 + Merged the follwing sns modifications into alh code: + + alCA.c - sinclair + Modified code in function description_callback + change pend io time from 0.5 to 5.0 seconds + add pend event poll after each pend io + + alLog.c, file.c - kasemir + Added xml flag. Log file is more XML-ish + + alLog.c, file.c - sinclair + added format specifier -xml + + awAlh.c, awView.c - sinclair + modified code associated with clipboard copy operation + on drag-and-drop operation, attempt to put pv name into + primary selection buffer + added code so a drag-and-drop operation displays the group + name or pv name; this may be used to examine the pv name associated + with an alias; to do this I needed to change user data associated + with group and pv name buttons + modified code to accommodate the above change in user data + code cleanup + + axArea.h - axRunW.c - sinclair + Environment variable ALHMAINFONT may be used to set top level button font + e.g. export ALHMAINFONT='-*-utopia-bold-r-normal--0-720-75-75-p-0-*-*' + Added code to display mask of top group in top level button label + + alLib.c - sinclair + code cleanup + added serveral NULL pointer checks + + alLib.c - axRunW.c - sinclair + show force mask on top button only when at least one bit is set + + axRunW.c.c - sinclair + code cleanup + changed if/then test condition + Enclose top level button mask info in < > + + process.c - sinclair + Change action separator from "|" to "!" + make command menu a child of topLevelShell + add code to allow multiple commands to be specified for one + command (corresponding to the old syntax) - execute when button is + pressed + multiple commands are designated using the following syntax + cmd 1 name|cmd 1 string|cmd 2 name|cmd 2 string|...cmd n name|cmd n string + for multiple commands, popup menu and execute the selected command + + scroll.c - sinclair + remove static qualifier from Strncat + change "/" to '/' in comparison + code cleanup + use configuration directory (if given) when building include file names + set maximum config file line length to 1023 + added code to recursively display contents of configuration include + files + +Tue Jun 26 14:16:33 CDT 2007 ALH_1_2_23 + Return val for calcPerform/postfix changed to long to match prototype + For WIN32 set strtok_r to strtok_s + +Mon Nov 5 15:56:00 CST 2007 + Bug fix. Initialized numChildren to zero in case the resource XmNnumChildren + is not defined for some Widgets. + +Mon Nov 26 10:11:55 CST 2007 + Put ALH User's Guide under CVS control in alh subdirectory documentation. + Updated User's Guide with SNS changes. (see entry of Jun 26). + +Tue Feb 5 10:19:30 CST 2008 ALH_1_2_24 + Portability changes for 64bit builds. diff --git a/alh.rc b/alh.rc new file mode 100644 index 0000000..4805160 --- /dev/null +++ b/alh.rc @@ -0,0 +1,39 @@ +#include +#include "version.h" +#include "epicsVersion.h" + +ALH_ICON ICON DISCARDABLE "alh.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION ALH_VERSION,ALH_REVISION,ALH_MODIFICATION,0 + PRODUCTVERSION EPICS_VERSION,EPICS_REVISION,EPICS_MODIFICATION,EPICS_PATCH_LEVEL + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments","Alarm handler for EPICS\0" + VALUE "CompanyName", "Argonne National Laboratory\0" + VALUE "FileDescription", "Alarm Handler for EPICS\0" + VALUE "FileVersion", ALH_VERSION_STRING "\0" + VALUE "InternalName", "alh\0" + VALUE "LegalCopyright", "Copyright (C) Univ. of California, Univ. of Chicago\0" + VALUE "OriginalFilename", "alh.exe\0" + VALUE "ProductName", "Experimental Physics and Industrial Control System (EPICS)\0" + VALUE "ProductVersion", EPICS_VERSION_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/alh_DB.c b/alh_DB.c new file mode 100644 index 0000000..057084c --- /dev/null +++ b/alh_DB.c @@ -0,0 +1,261 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/************************DESCRIPTION*********************************** + DataBase call routine. Work like independent process. +We have simple Perl call and more usefull C-RPC call. +rpc_gen X-files for RPC is : +struct DBSend {string msg<>;}; +program DB_PORT { + version DB_VERS { + void dbSend(DBSend) = 1; + } =1; +}=port; +**********************************************************************/ + +#define C_CALL +#undef PERL_CALL +/* #define PERL_CALL */ + +#include +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#endif +#ifdef HAVE_SYSV_IPC +#include +#endif +#include + +#ifdef PERL_CALL +#include +#include +#include +#include +#include +#include +int TCPInit(char *hostname,int port); +int put2TCP(char *hostname,int port,char *string,int len); +#endif + +#ifdef C_CALL +#include +struct DBSend { + char *msg; +}; +typedef struct DBSend DBSend; +#define DB_VERS ((unsigned long)(1)) +#define dbSend ((unsigned long)(1)) +extern void * dbsend_1(); +extern bool_t xdr_DBSend(); +static struct timeval TIMEOUT = { 10, 0 }; +#endif + +#define DEBUG 1 + +int put2RPC(char *host ,int port,char *msg,int len); + +char msg[250]; + +int main(argc,argv) +int argc; +char *argv[]; +{ +struct msqid_ds infoBuf; +int DBMsgQId; +int DBMsgQKey; +int port; +int bytes=250; +int socket; + + if (argc != 4) { + fprintf(stderr,"usage:%s TCPName TCPport Key\n",argv[0]); + exit(1); + } + if ( !(DBMsgQKey=atoi(argv[3])) || !(port=atoi(argv[2])) ) { + fprintf(stderr,"usage:%s TCPName TCPport Key\n",argv[0]); + exit(1); + } + + DBMsgQId = msgget (DBMsgQKey, 0600|IPC_CREAT); + if(DBMsgQId == -1) {perror("msgQ_create"); exit(1);} + else + { + fprintf(stderr,"msgQ with key=%d is OK\n",DBMsgQKey); + if (msgctl(DBMsgQId,IPC_STAT,&infoBuf) != 1) + { + fprintf(stderr,"owner = %d.%d, perms = %04o, max bytes = %d\n", + infoBuf.msg_perm.uid,infoBuf.msg_perm.gid, + infoBuf.msg_perm.mode,infoBuf.msg_qbytes); + fprintf(stderr,"%d msgs = %d bytes on queue\n", + infoBuf.msg_qnum, infoBuf.msg_cbytes); + } + else {perror("msgctl()"); exit(1);} + } +#ifdef PERL_CALL + fprintf(stderr,"Please wait ...\n"); + if( (socket=TCPInit(argv[1],port)) <= 0 ) { + perror("can't connect to TCP task"); + exit(1); + } + else fprintf(stderr,"TCPInit for %s port=%d is OK\n",argv[1],port); + close(socket); + sleep(2); +#endif + if(DEBUG) fprintf(stderr,"star\n"); + + while(1) + { + if( msgrcv(DBMsgQId,msg,bytes,0,0) >= 0) /* got a new message */ + { + if(DEBUG) fprintf(stderr,"msg=%s\n",msg); +#ifdef C_CALL + put2RPC(argv[1],port,msg,strlen(msg)); +#else + put2TCP(argv[1],port,msg,strlen(msg)); +#endif + } + else usleep(1000); /* # in microsec */ + } + +} + +#ifdef C_CALL +int put2RPC(char *host ,int port,char *msg,int len) +{ + CLIENT *clnt; + void *result_1; + DBSend dbsend_1_arg; + dbsend_1_arg.msg=msg; + + clnt = clnt_create(host, port, DB_VERS, "netpath"); + if (clnt == (CLIENT *) NULL) { + clnt_pcreateerror(host); + return(-1); + } + result_1 = dbsend_1(&dbsend_1_arg, clnt); + if (result_1 == (void *) NULL) { + clnt_perror(clnt, "call failed"); + } + clnt_destroy(clnt); +return (0); +} +void * +dbsend_1(argp, clnt) + DBSend *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof (clnt_res)); + if (clnt_call(clnt, dbSend, + (xdrproc_t) xdr_DBSend, (caddr_t) argp, + (xdrproc_t) xdr_void, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +bool_t +xdr_DBSend(xdrs, objp) + register XDR *xdrs; + DBSend *objp; +{ + + register long *buf; + + if (!xdr_string(xdrs, &objp->msg, ~0)) + return (FALSE); + return (TRUE); +} +#endif + +#ifdef PERL_CALL +int TCPInit(char *hostname,int port) +{ +int DBSocket; +struct sockaddr_in s_name; +struct hostent *h_ptr; +int true=1; + +if ((DBSocket=socket(AF_INET, SOCK_STREAM, 0)) == -1){ + perror( "socket"); + return(-1); +} + +if ((h_ptr = gethostbyname(hostname)) == NULL ) + { + perror("gethostbyname"); + exit(1); + } + +memset(&s_name, 0, sizeof(s_name)); +s_name.sin_family = AF_INET; +s_name.sin_port = htons(port); +memcpy(&s_name.sin_addr, h_ptr->h_addr, sizeof (s_name.sin_addr)); + +true=1; +if(setsockopt(DBSocket,SOL_SOCKET,SO_KEEPALIVE,(char *)&true,sizeof(true))) { + perror("Keepalive option set failed"); + return(-1); + } +true=1; + +if(setsockopt(DBSocket,IPPROTO_TCP,TCP_NODELAY,(char *)&true,sizeof(true))){ + perror("nodelay option set failed"); + return(-1); + } +true=200; +if(setsockopt(DBSocket,SOL_SOCKET,SO_SNDBUF,(char *)&true,sizeof(true))){ + perror("sendbuf option set failed"); + return(-1); + } + +if (connect(DBSocket, (struct sockaddr *) &s_name, sizeof (s_name)) ) { + perror("connect"); + close(DBSocket); + return(-1); +} + +return(DBSocket); +} + + +int put2TCP(char *hostname,int port,char *string,int len) +{ +int DBSock; +int ret; + +while(1) + { + if( (DBSock=TCPInit(hostname,port)) <= 0) { + sleep(1); + continue; + } + ret=send(DBSock,string,len,0); + if (ret != strlen(string)) { + fprintf(stderr,"DB_call:Send_byte=%d need%d\n",ret,len); + } + close(DBSock); + usleep(1000); + return(0); + + } +} +#endif diff --git a/awAct.c b/awAct.c new file mode 100644 index 0000000..0b56c22 --- /dev/null +++ b/awAct.c @@ -0,0 +1,728 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* awAct.c */ + +/************************DESCRIPTION*********************************** + Routines for alarm configuration tool (act) mode +**********************************************************************/ + +#include + +#include +#include +#include + +#include "alh.h" +#include "ax.h" +#include "alLib.h" +#include "axArea.h" +#include "epicsVersion.h" +#include "version.h" + +#define KEEP 0 +#define ALH_DELETE 1 + +/* act menu definitions */ +#define MENU_FILE_NEW 10100 +#define MENU_FILE_OPEN 10101 +#define MENU_FILE_OPEN_OK 10102 +#define MENU_FILE_CLOSE 10103 +#define MENU_FILE_CLOSEALL 10104 +#define MENU_FILE_SAVE 10105 +#define MENU_FILE_SAVEAS 10106 +#define MENU_FILE_ALH 10107 +#define MENU_FILE_PRINT 10108 +#define MENU_FILE_QUIT 10109 + +#define MENU_VIEW_EXPANDCOLLAPSE1 10200 +#define MENU_VIEW_EXPANDBRANCH 10201 +#define MENU_VIEW_EXPANDALL 10202 +#define MENU_VIEW_COLLAPSEBRANCH 10203 +#define MENU_VIEW_PROPERTIES 10204 + +#define MENU_EDIT_UNDO 10600 +#define MENU_EDIT_CUT 10601 +#define MENU_EDIT_COPY 10602 +#define MENU_EDIT_PASTE 10603 +#define MENU_EDIT_CLEAR 10604 +#define MENU_EDIT_CLEAR_OK 10605 + +#define MENU_INSERT_GROUP 10800 +#define MENU_INSERT_CHANNEL 10801 +#define MENU_INSERT_INCLUDE 10802 +#define MENU_INSERT_FILE 10803 +#define MENU_INSERT_SETTINGS 10804 + +#define MENU_HELP_HELP 10900 +#define MENU_HELP_ABOUT 10906 + +/* external variables */ +extern ALINK *alhArea; +extern char alhVersionString[100]; + +/* prototypes for static routines */ +static void actFileCallback(Widget widget, XtPointer calldata, XtPointer cbs); +static void actEditCallback(Widget widget, XtPointer calldata, XtPointer cbs); +static void actInsertCallback(Widget widget, XtPointer calldata, XtPointer cbs); +static void actViewCallback(Widget widget, XtPointer calldata, XtPointer cbs); +static void actHelpCallback(Widget widget, XtPointer calldata, XtPointer cbs); +static int checkActiveSelection(ALINK *area); +static int checkActiveSelectionMainGroup(ALINK *area); + + +/****************************************************** + Create ACT MenuBar +******************************************************/ +Widget actCreateMenu(Widget parent,XtPointer user_data) +{ + Widget widget; + static MenuItem file_menu[] = { + /* + { "New", PushButtonGadgetClass, 'N', "CtrlN", "Ctrl+N", + actFileCallback, (XtPointer)MENU_FILE_NEW, (MenuItem *)NULL }, + */ + { "Open ...", PushButtonGadgetClass, 'O', "CtrlO", "Ctrl+O", + actFileCallback, (XtPointer)MENU_FILE_OPEN, (MenuItem *)NULL }, + /* + { "Close", PushButtonGadgetClass, 'C', NULL, NULL, + actFileCallback, (XtPointer)MENU_FILE_CLOSE, (MenuItem *)NULL }, + { "Close All", PushButtonGadgetClass, 'A', NULL, NULL, + actFileCallback, (XtPointer)MENU_FILE_CLOSEALL, (MenuItem *)NULL }, + */ + { "Save", PushButtonGadgetClass, 'S', "CtrlS", "Ctrl+S", + actFileCallback, (XtPointer)MENU_FILE_SAVE, (MenuItem *)NULL }, + { "Save As ...",PushButtonGadgetClass, 'A', NULL, NULL, + actFileCallback, (XtPointer)MENU_FILE_SAVEAS, (MenuItem *)NULL }, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL }, + { "Activate ALH ...", PushButtonGadgetClass, 'A', NULL, NULL, + actFileCallback, (XtPointer)MENU_FILE_ALH, (MenuItem *)NULL }, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL }, + { "Tree Report ...", PushButtonGadgetClass, 'P', NULL, NULL, + actFileCallback, (XtPointer)MENU_FILE_PRINT, (MenuItem *)NULL }, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL }, + { "Exit", PushButtonGadgetClass, 'X', "CtrlX", "Ctrl+X", + actFileCallback, (XtPointer)MENU_FILE_QUIT, (MenuItem *)NULL }, + {NULL}, + }; + + static MenuItem edit_menu[] = { + + /* ACCELERATORS DONT WORK YET + { "Undo", PushButtonGadgetClass, 'U', "AltBackSpace", "Alt+BackSpace", + actEditCallback, (XtPointer)MENU_EDIT_UNDO, (MenuItem *)NULL }, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL }, + { "Cut", PushButtonGadgetClass, 't', "ShiftDelete", "Shift+Del", + actEditCallback, (XtPointer)MENU_EDIT_CUT, (MenuItem *)NULL }, + { "Copy", PushButtonGadgetClass, 'C', "CtrlInsert", "Ctrl+Ins", + actEditCallback, (XtPointer)MENU_EDIT_COPY, (MenuItem *)NULL }, + { "Paste", PushButtonGadgetClass, 'P', "ShiftInsert", "Shift+Ins", + actEditCallback, (XtPointer)MENU_EDIT_PASTE, (MenuItem *)NULL }, + */ + /* UNDO DOES NOT WORK YET + { "Undo", PushButtonGadgetClass, 'U', NULL, NULL, + actEditCallback, (XtPointer)MENU_EDIT_UNDO, (MenuItem *)NULL }, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL }, + */ + { "Cut", PushButtonGadgetClass, 't', NULL, NULL, + actEditCallback, (XtPointer)MENU_EDIT_CUT, (MenuItem *)NULL }, + { "Copy", PushButtonGadgetClass, 'C', NULL, NULL, + actEditCallback, (XtPointer)MENU_EDIT_COPY, (MenuItem *)NULL }, + { "Paste", PushButtonGadgetClass, 'P', NULL, NULL, + actEditCallback, (XtPointer)MENU_EDIT_PASTE, (MenuItem *)NULL }, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL }, + { "Clear", PushButtonGadgetClass, 'e', NULL, NULL, + actEditCallback, (XtPointer)MENU_EDIT_CLEAR, (MenuItem *)NULL }, + {NULL}, + }; + + static MenuItem insert_menu[] = { + { "Group ...", PushButtonGadgetClass, 'G', NULL, NULL, + actInsertCallback, (XtPointer)MENU_INSERT_GROUP, (MenuItem *)NULL }, + { "Channel ...", PushButtonGadgetClass, 'C', NULL, NULL, + actInsertCallback, (XtPointer)MENU_INSERT_CHANNEL, (MenuItem *)NULL }, + { "Runtime Include...", PushButtonGadgetClass, 'F', NULL, NULL, + actInsertCallback, (XtPointer)MENU_INSERT_INCLUDE, (MenuItem *)NULL }, + { "File ...", PushButtonGadgetClass, 'F', NULL, NULL, + actInsertCallback, (XtPointer)MENU_INSERT_FILE, (MenuItem *)NULL }, + {NULL}, + }; + + static MenuItem view_menu[] = { + { "Expand One Level", PushButtonGadgetClass, 'O', "Noneplus", "+", + actViewCallback, (XtPointer)MENU_VIEW_EXPANDCOLLAPSE1, (MenuItem *)NULL }, + { "Expand Branch", PushButtonGadgetClass, 'B', "Noneasterisk", "*", + actViewCallback, (XtPointer)MENU_VIEW_EXPANDBRANCH, (MenuItem *)NULL }, + { "Expand All", PushButtonGadgetClass, 'A',"Ctrlasterisk", "Ctrl+*", + actViewCallback, (XtPointer)MENU_VIEW_EXPANDALL, (MenuItem *)NULL }, + { "Collapse Branch", PushButtonGadgetClass, 'C', "Noneminus", "-", + actViewCallback, (XtPointer)MENU_VIEW_COLLAPSEBRANCH, (MenuItem *)NULL }, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL }, + { "Properties Window", ToggleButtonGadgetClass, 'W', NULL, NULL, + actViewCallback, (XtPointer)MENU_VIEW_PROPERTIES, (MenuItem *)NULL }, + {NULL}, + }; + + static MenuItem help_menu[] = { + /* HELP NOT IMPLEMENTED YET + { "Help Topics", PushButtonGadgetClass, 'H', NULL, NULL, + actHelpCallback, (XtPointer)MENU_HELP_TOPICS, (MenuItem *)NULL }, + */ + #if XmVersion && XmVersion >= 1002 + { "About ALH", PushButtonGadgetClass, 'A', NULL, NULL, + actHelpCallback, (XtPointer)MENU_HELP_ABOUT, (MenuItem *)NULL }, + #endif + {NULL}, + }; + + Widget menubar; + + menubar = XmCreateMenuBar(parent, "menubar", NULL, 0); + + XtVaSetValues(menubar, XmNshadowThickness, 0, NULL); + + widget = buildPulldownMenu(menubar, "File", 'F', TRUE, file_menu, user_data); + widget = buildPulldownMenu(menubar, "Edit", 'E', TRUE, edit_menu, user_data); + widget = buildPulldownMenu(menubar, "Insert",'I', TRUE, insert_menu, user_data); + widget = buildPulldownMenu(menubar, "View", 'V', TRUE, view_menu, user_data); + widget = buildPulldownMenu(menubar, "Help", 'H', TRUE, help_menu, user_data); + + /* Make sure Help on MenuBar item is right adjusted */ + XtVaSetValues(menubar, XmNtopAttachment, XmATTACH_FORM, NULL); + XtVaSetValues(menubar, XmNrightAttachment, XmATTACH_FORM, NULL); + XtVaSetValues(menubar, XmNleftAttachment, XmATTACH_FORM, NULL); + XtVaSetValues(menubar, XmNmenuHelpWidget, widget, NULL); + + XtManageChild(menubar); + + return(menubar); +} + + +/****************************************************** + actFileCallback +******************************************************/ +static void actFileCallback(Widget widget, XtPointer calldata, XtPointer cbs) +{ + ALINK *area; + int item=(long)calldata; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + switch (item){ + + case MENU_FILE_NEW: + break; + + case MENU_FILE_OPEN: + + /* Display the config_changed warning dialog */ + if (area->changed){ + createActionDialog(area->form_main,XmDIALOG_WARNING, + "Latest configuration changes have not been saved. Continue?" , + (XtCallbackProc)actFileCallback,(XtPointer)MENU_FILE_OPEN_OK,(XtPointer)area); + break; + } + area->managed = FALSE; + createFileDialog(area->form_main,(void *)fileSetupCallback, + (XtPointer)FILE_CONFIG,(void *)fileCancelCallback, + (XtPointer)area, (XtPointer)area, "Config File",CONFIG_PATTERN,psetup.configDir); + break; + + case MENU_FILE_OPEN_OK: + + area->managed = FALSE; + createFileDialog(area->form_main,(void *)fileSetupCallback, + (XtPointer)FILE_CONFIG,(void *)fileCancelCallback, + (XtPointer)area, (XtPointer)area, "Config File",CONFIG_PATTERN,psetup.configDir); + break; + + case MENU_FILE_CLOSE: + break; + + case MENU_FILE_CLOSEALL: + break; + + case MENU_FILE_SAVEAS: + + /* New Name for Save Config File */ + createFileDialog(area->form_main,(void *)fileSetupCallback, + (XtPointer)FILE_SAVEAS,(void *)XtUnmanageChild,(XtPointer)0, + (XtPointer)area, "Save Config File",CONFIG_PATTERN,'\0'); + break; + + case MENU_FILE_SAVE: + + alLogOpModMessage(0,0, + "Setup Save New Config: %s",psetup.configFile); + alWriteConfig(psetup.configFile,area->pmainGroup); + break; + + case MENU_FILE_ALH: + + if (alhArea) alhArea->managed = FALSE; + setupConfig("",ALH,area); + + /* Display the config_changed warning dialog */ + /* + if (area->changed){ + createActionDialog(area->form_main,XmDIALOG_WARNING, + "Latest configuration changes have not been saved. Continue?" , + (XtCallbackProc)actInvokeAlhCallback, + (XtPointer)area,(XtPointer)area); + break; + } + */ + break; + + + case MENU_FILE_PRINT: + + /* Name for PrintTree Report */ + createFileDialog(area->form_main,(void *)fileSetupCallback, + (XtPointer)FILE_PRINT,(void *)XtUnmanageChild,(XtPointer)0, + (XtPointer)area, "Report File ",TREEREPORT_PATTERN,'\0'); + break; + + case MENU_FILE_QUIT: + + if (area->changed){ + /* Display the config_changed warning dialog */ + createActionDialog(area->form_main,XmDIALOG_WARNING, + "Latest configuration changes have not been saved! Exit Alarm Configuration Tool?", + (XtCallbackProc)exit_quit, + (XtPointer)area, (XtPointer)area); + break; + } + createActionDialog(area->form_main,XmDIALOG_WARNING,"Exit Alarm Configuration Tool?", + (XtCallbackProc)exit_quit, + (XtPointer)area, (XtPointer)area); + break; + + default: + + createDialog(area->form_main,XmDIALOG_INFORMATION,"Selection not implemented yet."," "); + break; + } +} + +/****************************************************** + actEditCallback +******************************************************/ +static void actEditCallback(Widget widget, XtPointer calldata, XtPointer cbs) +{ + int item=(long)calldata; + ALINK *area; + GCLINK *link; + GCLINK *next; + GCLINK *configLink; + int linkType; + int command; + GCLINK *tempLink; + int tempLinkType; + struct anyLine *treeLine; + struct anyLine *groupLine; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + switch (item){ + + case MENU_EDIT_CLEAR: + + if (area->changed){ + /* Display the config_changed warning dialog */ + createActionDialog(area->form_main,XmDIALOG_WARNING, + "Latest configuration changes have not been saved. Continue?" , + (XtCallbackProc)actEditCallback, + (XtPointer)MENU_EDIT_CLEAR_OK,(XtPointer)area); + break; + } + + case MENU_EDIT_CLEAR_OK: + + editUndoSet((GCLINK *)sllFirst(area->pmainGroup), + GROUP, NULL, MENU_EDIT_UNDO_CLEAR, ALH_DELETE); + + area->managed = FALSE; + area->pmainGroup->p1stgroup = NULL; + setupConfig("",ACT,area); + break; + + case MENU_EDIT_CUT: + + if (checkActiveSelection(area) ) break; + + if (checkActiveSelectionMainGroup(area) ) break; + + link = (GCLINK *)area->selectionLink; + linkType = area->selectionType; + + editClipboardSet(link, linkType); + + editUndoSet(link, linkType, NULL, MENU_EDIT_UNDO_PASTE, ALH_DELETE); + + editCutLink(area,link,linkType); + + break; + + case MENU_EDIT_COPY: + + if (checkActiveSelection(area) ) break; + + link = (GCLINK *)area->selectionLink; + linkType = area->selectionType; + + editClipboardSet(link, linkType); + + break; + + case MENU_EDIT_PASTE: + + if (checkActiveSelection(area) ) break; + + editClipboardGet(&link, &linkType); + + if (link) editPasteLink(area,link,linkType); + + break; + + case MENU_EDIT_UNDO: + + command = editUndoGetCommand(); + + switch (command){ + + case MENU_EDIT_UNDO_UPDATE_CLIPBOARD: + + editClipboardGet(&tempLink, &tempLinkType); + + editUndoGet(&link, &linkType, &configLink); + + editClipboardSet(link, linkType); + + editUndoSet(tempLink, tempLinkType, NULL, MENU_EDIT_UNDO_UPDATE_CLIPBOARD, KEEP); + + break; + + case MENU_EDIT_UNDO_PASTE: + + editUndoGet(&link, &linkType, &tempLink); + + next = (GCLINK *)sllNext((SNODE*)link); + if (next){ + ((struct subWindow *)area->groupWindow)->selectionLink=next; + area->selectionLink=next; + area->selectionType=linkType; + area->selectionWindow=area->groupWindow; + } else { + ((struct subWindow *)area->treeWindow)->selectionLink=link->parent; + area->selectionLink=link->parent; + area->selectionType=GROUP; + area->selectionWindow=area->treeWindow; + } + + editPasteLink(area,link,linkType); + + /* restore selection */ + groupLine = (struct anyLine *)link->lineGroupW; + treeLine = (struct anyLine *)link->lineTreeW; + if (groupLine){ + markSelectedWidget( area->groupWindow, ((WLINE *)groupLine->wline)->name); + markSelection( area->groupWindow, groupLine); + } else if (treeLine) { + markSelectedWidget( area->treeWindow, ((WLINE *)treeLine->wline)->name); + markSelection( area->treeWindow, treeLine); + } + + /* update dialog windows */ + axUpdateDialogs(area); + + /* update undo values */ + editUndoSet(NULL, linkType, link, MENU_EDIT_UNDO_CUT, KEEP); + + break; + + case MENU_EDIT_UNDO_PASTE_NOSELECT: + + editUndoGet(&link, &linkType, &tempLink); + + editPasteLink(area,link,linkType); + + /* update dialog windows */ + axUpdateDialogs(area); + + /* update undo values */ + editUndoSet(NULL, linkType, link, MENU_EDIT_UNDO_CUT_NOSELECT, KEEP); + + break; + + case MENU_EDIT_UNDO_CUT: + + if (checkActiveSelection(area) ) break; + + if (checkActiveSelectionMainGroup(area) ) break; + + link = (GCLINK *)area->selectionLink; + linkType = area->selectionType; + + editClipboardSet(link, linkType); + + editUndoSet(link, linkType, NULL, MENU_EDIT_UNDO_PASTE, KEEP); + + editCutLink(area,link,linkType); + + break; + + case MENU_EDIT_UNDO_CUT_NOSELECT: + + editUndoGet(&tempLink, &linkType, &link); + + editCutLink(area, link, linkType); + + editUndoSet(link, linkType, NULL, MENU_EDIT_UNDO_PASTE_NOSELECT, KEEP); + + /* update dialog windows */ + axUpdateDialogs(area); + + break; + + case MENU_EDIT_UNDO_PROPERTIES: + + propUndo(area); + + break; + + case MENU_EDIT_UNDO_CLEAR: + + link = (GCLINK *)sllFirst(area->pmainGroup); + editUndoGet(&tempLink, &linkType, &configLink); + area->pmainGroup->p1stgroup = (GLINK *)tempLink; + + editUndoSet(link, GROUP, 0, MENU_EDIT_UNDO_CLEAR, KEEP); + + setParentLink(area->treeWindow,area->pmainGroup->p1stgroup); + setParentLink(area->groupWindow,area->pmainGroup->p1stgroup); + ((struct subWindow *)area->treeWindow)->viewOffset = 0; + setViewConfigCount(area->treeWindow,area->pmainGroup->p1stgroup->viewCount); + + /* redraw main windows */ + redraw(area->treeWindow,0); + defaultTreeSelection(area); + + /* update dialog windows */ + axUpdateDialogs(area); + + break; + + default: + createDialog(area->form_main,XmDIALOG_INFORMATION, + "Selection not implemented yet."," "); + break; + } + + break; + + default: + + createDialog(area->form_main,XmDIALOG_INFORMATION,"Selection not implemented yet."," "); + break; + } +} + +/****************************************************** + actInsertCallback +******************************************************/ +static void actInsertCallback(Widget widget, XtPointer calldata, XtPointer cbs) +{ + int item=(long)calldata; + ALINK *area; + GCLINK *link; + int linkType; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + switch (item){ + + case MENU_INSERT_GROUP: + + if (checkActiveSelection(area) ) break; + + /* create a new Group */ + link = (GCLINK *)alCreateGroup(); + link->viewCount = 1; + linkType = GROUP; + + editPasteLink(area,link,linkType); + + break; + + case MENU_INSERT_CHANNEL: + + if (checkActiveSelection(area) ) break; + + /* create a new Channel */ + link = (GCLINK *)alCreateChannel(); + linkType = CHANNEL; + + editPasteLink(area, link, linkType); + + break; + + case MENU_INSERT_FILE: + + if (checkActiveSelection(area) ) break; + + area->managed = FALSE; + createFileDialog(area->form_main,(void *)fileSetupCallback, + (XtPointer)FILE_CONFIG_INSERT,(void *)XtUnmanageChild, + (XtPointer)0,(XtPointer)area, "Config File",CONFIG_PATTERN, + psetup.configDir); + break; + + default: + + createDialog(area->form_main,XmDIALOG_INFORMATION, + "Selection not implemented yet."," "); + break; + } + +} + +/****************************************************** + actViewCallback +******************************************************/ +static void actViewCallback(Widget widget, XtPointer calldata, XtPointer cbs) +{ + int item=(long)calldata; + ALINK *area; + void *link; + struct subWindow *treeWindow; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + treeWindow = (struct subWindow *)area->treeWindow; + + switch (item){ + + case MENU_VIEW_EXPANDCOLLAPSE1: + + /* Expand 1 level */ + link = treeWindow->selectionLink; + if (link) displayNewViewTree(area,link,EXPANDCOLLAPSE1); + else createDialog(area->form_main,XmDIALOG_WARNING, + "Please select an alarm group first."," "); + break; + + case MENU_VIEW_EXPANDBRANCH: + + /* Expand Branch */ + link = treeWindow->selectionLink; + if (link )displayNewViewTree(area,link,EXPAND); + else createDialog(area->form_main,XmDIALOG_WARNING, + "Please select an alarm group first."," "); + break; + + case MENU_VIEW_EXPANDALL: + + /* Expand all */ + displayNewViewTree(area,(GLINK *)sllFirst(area->pmainGroup),EXPAND); + break; + + case MENU_VIEW_COLLAPSEBRANCH: + + /* Collapse branch */ + link = treeWindow->selectionLink; + if (link )displayNewViewTree(area,link,COLLAPSE); + else createDialog(area->form_main,XmDIALOG_WARNING, + "Please select an alarm group first."," "); + break; + + case MENU_VIEW_PROPERTIES: + + propShowDialog(area, widget); + break; + + default: + + createDialog(area->form_main,XmDIALOG_INFORMATION, + "Selection not implemented yet."," "); + break; + } +} + + +/****************************************************** + actHelpCallback +******************************************************/ +static void actHelpCallback(Widget widget, XtPointer calldata, XtPointer cbs) +{ + int item=(long)calldata; + ALINK *area; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + switch (item){ + + case MENU_HELP_ABOUT: + createDialog(area->form_main,XmDIALOG_INFORMATION, + "\nAlarm Configuration Tool\n\n" ALH_CREDITS_STRING, + alhVersionString); + + break; + + default: + + createDialog(area->form_main,XmDIALOG_INFORMATION, + "Help is not available in this release."," "); + break; + } +} + +/****************************************************** + checkActiveSelection +******************************************************/ +static int checkActiveSelection(area) +ALINK *area; +{ + + if (!area->selectionLink){ + createDialog(area->form_main,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + return 1; + } + return 0; +} + +/****************************************************** + checkActiveSelectionMainGroup +******************************************************/ +static int checkActiveSelectionMainGroup(area) +ALINK *area; +{ + GCLINK *link; + + link = (GCLINK *)area->selectionLink; + if (!link->parent){ + createDialog(area->form_main,XmDIALOG_ERROR,link->pgcData->name, + " is main group and cannot be deleted"); + return 1; + } + return 0; +} diff --git a/awAlh.c b/awAlh.c new file mode 100644 index 0000000..96a0acc --- /dev/null +++ b/awAlh.c @@ -0,0 +1,1916 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* awAlh.c */ + +/************************DESCRIPTION*********************************** + This file contains routines for alh menu. +**********************************************************************/ + +/****************************************************************** + Public routines defined in awAlh.c + +Widget alhCreateMenu(parent, user_data) Create alh pulldown Menu +void alhFileCallback(widget, item, cbs) File menu items callback +void alhActionCallback(widget, item, cbs) Action menu items callback +void alhViewCallback(widget, item, cbs) View menu items callback +void alhSetupCallback(widget, item, cbs) Setup menu items callback +void alhHelpCallback(widget, item, cbs) Help menu items callback +void awRowWidgets(line, area) Create line widgets +void awUpdateRowWidgets(line) Update line widgets + +**************************************************************************/ + +#include +#include +#ifndef WIN32 +#include +#include +#endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alarm.h" +#include "epicsVersion.h" + +#include "ax.h" +#include "alh.h" +#include "axArea.h" +#include "axSubW.h" +#include "line.h" +#include "alLib.h" +#include "sllLib.h" +#include "version.h" +#include "alAudio.h" + +/* menu definitions */ +#define MENU_FILE_OPEN 10101 +#define MENU_FILE_OPEN_OK 10102 +#define MENU_FILE_CLOSE 10103 +#define MENU_FILE_SAVEAS 10106 +#define MENU_FILE_QUIT 10109 + +#define MENU_VIEW_EXPANDCOLLAPSE1 10200 +#define MENU_VIEW_EXPANDBRANCH 10201 +#define MENU_VIEW_EXPANDALL 10202 +#define MENU_VIEW_COLLAPSEBRANCH 10203 +#define MENU_VIEW_PROPERTIES 10204 + +#define MENU_ACTION_ACK 10300 +#define MENU_ACTION_GUIDANCE 10301 +#define MENU_ACTION_PROCESS 10302 +#define MENU_ACTION_FORCEPV 10303 +#define MENU_ACTION_FORCE_MASK 10304 +#define MENU_ACTION_MODIFY_MASK 10305 +#define MENU_ACTION_BEEPSEVR 10306 +#define MENU_ACTION_NOACKTIMER 10307 + + +#define MENU_VIEW_CONFIG 10400 +#define MENU_VIEW_OPMOD 10401 +#define MENU_VIEW_ALARMLOG 10402 +#define MENU_VIEW_CURRENT 10403 +#define MENU_VIEW_CMLOG 10404 + +#define MENU_SETUP_BEEP_MINOR 10500 +#define MENU_SETUP_BEEP_MAJOR 10501 +#define MENU_SETUP_BEEP_INVALID 10502 +#define MENU_SETUP_FILTER_NONE 10503 +#define MENU_SETUP_FILTER_ACTIVE 10504 +#define MENU_SETUP_FILTER_UNACK 10505 +#define MENU_SETUP_SILENCE_FOREVER 10506 +#define MENU_SETUP_ALARMLOG 10507 +#define MENU_SETUP_OPMOD 10508 + +#define MENU_ACTION_BEEP_MINOR 10500 +#define MENU_ACTION_BEEP_MAJOR 10501 +#define MENU_ACTION_BEEP_INVALID 10502 + +#define MENU_HELP_HELP 10900 +#define MENU_HELP_ABOUT 10906 + +/* external variables */ +extern char alhVersionString[100]; +extern char *bg_char[]; +extern Pixel bg_pixel[]; +extern Pixel channel_bg_pixel; +extern struct setup psetup; +extern Widget versionPopup; +extern int _message_broadcast_flag; /* messages sending flag. Albert1*/ +extern int messBroadcastDeskriptor; +extern char messBroadcastInfoFileName[250]; +int messBroadcastLockDelay=60000; /* 1 min */ +extern char *reloadMBString; +extern char *rebootString; +extern int max_not_save_time; +extern int amIsender; +extern int DEBUG; +extern int _main_window_flag; +char FS_filename[128]; /* Filename for FSBox. Albert*/ + +struct UserInfo { +char *loginid; +char *real_world_name; +char *myhostname; +char *displayName; +}; + +extern struct UserInfo userID; /* info about current operator */ + +/* prototypes for static routines */ +static void alhFileCallback( Widget widget, XtPointer calldata, XtPointer cbs); +static void alhActionCallback( Widget widget, XtPointer calldata, XtPointer cbs); +static void alhViewCallback( Widget widget, XtPointer calldata, XtPointer cbs); +static void alhViewBrowserCallback( Widget widget, XtPointer item, XtPointer cbs); /* Albert1 */ +static void messBroadcast(Widget widget, XtPointer item, XtPointer cbs); /* Albert1 */ +static void alhSetupCallback( Widget widget, XtPointer calldata, XtPointer cbs); +static void alhHelpCallback( Widget widget, XtPointer calldata, XtPointer cbs); +static void browserFBSDialogCbOk(); /* Ok-button for FSBox. Albert*/ +static void browserFBSDialogCbCancel(); /* Cancel-button for FSBox. Albert*/ +static void writeMessBroadcast(Widget dialog, Widget text_w); +static void helpMessBroadcast(Widget,XtPointer,XtPointer); +static void cancelMessBroadcast(Widget w); +static void messBroadcastFileUnlock(); + +#ifdef CMLOG +static void awCMLOGstartBrowser(void); +#endif + + + +static void drag ( + Widget w, + XEvent *e, + String *params, + Cardinal numParams ); + +static void dummy ( + Widget w, + XEvent *e, + String *params, + Cardinal numParams ); + +static int g_transInit = 1; +static XtTranslations g_parsedTrans; + +static char g_dragTrans[] = + "~Ctrl~Shift: startDrag()\n\ + Ctrl~Shift: dummy()\n\ + Shift~Ctrl: dummy()\n\ + Shift Ctrl: dummy()\n\ + Shift Ctrl: dummy()\n\ + Shift~Ctrl: dummy()"; + +static XtActionsRec g_dragActions[] = { + { "startDrag", (XtActionProc) drag }, + { "dummy", (XtActionProc) dummy } +}; + +static int g_ddFixedFont_created = 0; +static XFontStruct *g_ddFixedFont = NULL; + +static int g_ddgc_created = 0; +static GC g_ddgc = NULL; + +static void dragFin ( + Widget w, + XtPointer clientData, + XtPointer call_data ) +{ + +Widget icon; + + icon = NULL; + + XtVaGetValues( w, XmNsourcePixmapIcon, &icon, NULL ); + + if ( icon ) { + XtDestroyWidget( icon ); + } + +} + +static Boolean cvtSel ( + Widget w, + Atom *selection, + Atom *target, + Atom *type_return, + XtPointer *value_return, + unsigned long *len_return, + int *format_return ) +{ + +struct anyLine *line; +int l; +char *pasteData; +char **value = (char**) value_return; +XSelectionRequestEvent* req; +Display* d = XtDisplay( w ); + + if ( *selection != XA_PRIMARY ) { + return FALSE; + } + + req = XtGetSelectionRequest( w, *selection, (XtRequestId) NULL ); + + XtVaGetValues( w, XmNuserData, &line, NULL ); + + if ( !line ) { + return FALSE; + } + + if ( !line->pname ) { + return FALSE; + } + + l = strlen( line->pname ); + if ( l < 1 ) { + return FALSE; + } + + if (*target == XA_TARGETS(d)) { + + Atom* targetP; + Atom* std_targets; + unsigned long std_length; + + XmuConvertStandardSelection( w, req->time, selection, target, type_return, + (XPointer*) &std_targets, &std_length, format_return ); + + *value = + (char*) XtMalloc( sizeof(Atom) * ( (unsigned) std_length + 5 ) ); + targetP = *( (Atom**) value ); + *targetP++ = XA_STRING; + *targetP++ = XA_TEXT(d); + *len_return = std_length + ( targetP - ( *(Atom **) value) ); + + memcpy( (void*) targetP, (void*) std_targets, + (size_t)( sizeof(Atom) * std_length ) ); + + XtFree( (char*) std_targets ); + + *type_return = XA_ATOM; + *format_return = 32; + + return True; + + } + + if ( *target == XA_STRING || + *target == XA_TEXT(d) || + *target == XA_COMPOUND_TEXT(d) ) { + + if ( *target == XA_COMPOUND_TEXT(d) ) { + *type_return = *target; + } + else { + *type_return = XA_STRING; + } + + pasteData = strdup( line->pname ); + + *value_return = pasteData; + *len_return = l; + *format_return = 8; + + return TRUE; + + } + + if ( XmuConvertStandardSelection( w, req->time, selection, target, + type_return, (XPointer *) value_return, len_return, format_return ) ) { + return True; + } + + return False; + +} + +static Boolean cvt ( + Widget w, + Atom *selection, + Atom *target, + Atom *type_return, + XtPointer *value_return, + unsigned long *len_return, + int *format_return ) +{ + +Display *d; +struct anyLine *line; +Atom MOTIF_DROP; +int l; +char *dragData; + + d = XtDisplay( w ); + MOTIF_DROP = XmInternAtom( d, "_MOTIF_DROP", FALSE ); + + if ( *selection != MOTIF_DROP ) { + return FALSE; + } + + if ( *target != XA_STRING ) { + return FALSE; + } + + XtVaGetValues( w, XmNclientData, &line, NULL ); + + if ( !line->pname ) { + return FALSE; + } + + l = strlen( line->pname ); + if ( l < 1 ) { + return FALSE; + } + + dragData = strdup( line->pname ); + + *type_return = *target; + *value_return = dragData; + *len_return = l+1; + *format_return = 8; + + return TRUE; + +} + +/* 21 Aug 01 16:04:30 Thomas Birke (Thomas.Birke@mail.bessy.de) + * + * Create a small pixmap to be set as the drag-icon and write the + * PV-names into the pixmap + */ + +static Widget mkDragIcon ( + Widget w, + struct anyLine *line +) { + + Arg args[8]; + Cardinal n; + Widget sourceIcon; + int textWidth=0, maxWidth, maxHeight, fontHeight; + unsigned long fg, bg; + XGCValues gcValues; + unsigned long gcValueMask; + char tmpStr[131+1], *str; + + Display *display = XtDisplay(w); + int screenNum = DefaultScreen(display); + + Pixmap sourcePixmap = (Pixmap)NULL; + + if ( !g_ddFixedFont_created ) { + g_ddFixedFont_created = 1; + g_ddFixedFont = XLoadQueryFont( display, "fixed" ); + } + +#define X_SHIFT 8 +#define MARGIN 2 + + bg = BlackPixel(display,screenNum); + fg = WhitePixel(display,screenNum); + + fontHeight = g_ddFixedFont->ascent + g_ddFixedFont->descent; + + strcpy( tmpStr, "[N/A]" ); + str = strdup( line->pname ); + if ( str ) { + strncpy( tmpStr, str, 131 ); + tmpStr[131] = 0; + } + + textWidth = XTextWidth( g_ddFixedFont, tmpStr, strlen(tmpStr) ); + + maxWidth = X_SHIFT + ( textWidth + MARGIN ); + maxHeight = fontHeight + 2 * MARGIN; + + sourcePixmap = XCreatePixmap(display, + RootWindow(display, screenNum), + maxWidth,maxHeight, + DefaultDepth(display,screenNum) ); + + if ( !g_ddgc_created ) { + g_ddgc_created = 1; + g_ddgc = XCreateGC( display, sourcePixmap, 0, NULL ); + } + + gcValueMask = GCForeground|GCBackground|GCFunction|GCFont; + + gcValues.foreground = bg; + gcValues.background = bg; + gcValues.function = GXcopy; + gcValues.font = g_ddFixedFont->fid; + + XChangeGC( display, g_ddgc, gcValueMask, &gcValues ); + + XFillRectangle( display, sourcePixmap, g_ddgc, 0, 0, maxWidth, + maxHeight); + + XSetForeground( display, g_ddgc, fg ); + + XDrawString( display, sourcePixmap, g_ddgc, + X_SHIFT, g_ddFixedFont->ascent + MARGIN, + tmpStr, strlen(tmpStr) ); + + n = 0; + XtSetArg(args[n],XmNpixmap,sourcePixmap); n++; + XtSetArg(args[n],XmNwidth,maxWidth); n++; + XtSetArg(args[n],XmNheight,maxHeight); n++; + XtSetArg(args[n],XmNdepth,DefaultDepth(display,screenNum)); n++; + sourceIcon = XmCreateDragIcon(XtParent(w),"sourceIcon",args,n); + + return sourceIcon; + +} + +static int startDrag ( + struct anyLine *line, + Widget w, + XEvent *e ) +{ + +Atom expList[1]; +int status, n; +Arg args[10]; +Widget dc; +Widget icon; + + /* attempt to put pv name into primary select buffer */ + if ( w ) { + XtDisownSelection( w, XA_PRIMARY, CurrentTime ); + status = XtOwnSelection( w, XA_PRIMARY, CurrentTime, + cvtSel, (XtLoseSelectionProc) 0, (XtSelectionDoneProc) 0 ); + } + + icon = mkDragIcon( w, line ); + if ( !icon ) return 0; + + expList[0] = XA_STRING; + n = 0; + XtSetArg( args[n], XmNexportTargets, expList ); n++; + XtSetArg( args[n], XmNnumExportTargets, 1 ); n++; + XtSetArg( args[n], XmNdragOperations, XmDROP_COPY ); n++; + XtSetArg( args[n], XmNconvertProc, cvt ); n++; + XtSetArg( args[n], XmNsourcePixmapIcon, icon ); n++; + XtSetArg( args[n], XmNclientData, (XtPointer) line ); n++; + + dc = XmDragStart( w, e, args, n ); + XtAddCallback( dc, XmNdragDropFinishCallback, dragFin, (XtPointer) line ); + + return 1; + +} + +static void drag ( + Widget w, + XEvent *e, + String *params, + Cardinal numParams ) +{ + +struct anyLine *line; +int stat; + + XtVaGetValues( w, XmNuserData, &line, NULL ); + + stat = startDrag( line, w, e ); + +} + +static void dummy ( + Widget w, + XEvent *e, + String *params, + Cardinal numParams ) +{ + +} + +/****************************************************** + alhCreateMenu +******************************************************/ + +/* Create ALH MenuBar */ +Widget alhCreateMenu(Widget parent,XtPointer user_data) +{ + static MenuItem file_menu[] = { + { "Open ...", PushButtonGadgetClass, 'O', "CtrlO", "Ctrl+O", + alhFileCallback, (XtPointer)MENU_FILE_OPEN, (MenuItem *)NULL, 0 }, + { "Save As ...",PushButtonGadgetClass, 'v', NULL, NULL, + alhFileCallback, (XtPointer)MENU_FILE_SAVEAS, (MenuItem *)NULL , 0}, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL }, + { "Close", PushButtonGadgetClass, 'C', NULL, NULL, + alhFileCallback, (XtPointer)MENU_FILE_CLOSE, (MenuItem *)NULL, 0 }, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL, 0 }, + {NULL}, + }; + + static MenuItem action_menu[] = { + { "Acknowledge Alarm", PushButtonGadgetClass, 'A', "CtrlA", "Ctrl+A", + alhActionCallback, (XtPointer)MENU_ACTION_ACK, (MenuItem *)NULL, 0 }, + { "Display Guidance", PushButtonGadgetClass, 'G', "CtrlG", "Ctrl+G", + alhActionCallback, (XtPointer)MENU_ACTION_GUIDANCE, (MenuItem *)NULL, 0 }, + { "Start Related Process", PushButtonGadgetClass, 'P', "CtrlP", "Ctrl+P", + alhActionCallback, (XtPointer)MENU_ACTION_PROCESS, (MenuItem *)NULL, 0 }, + { "Force Process Variable ...", ToggleButtonGadgetClass, 'V', "CtrlV", "Ctrl+V", + alhActionCallback, (XtPointer)MENU_ACTION_FORCEPV, (MenuItem *)NULL, 0 }, + { "Force Mask ...", ToggleButtonGadgetClass, 'M',"CtrlM", "Ctrl+M", + alhActionCallback, (XtPointer)MENU_ACTION_FORCE_MASK, (MenuItem *)NULL, 0 }, + { "Modify Mask Settings ...", ToggleButtonGadgetClass, 'S', "CtrlS", "Ctrl+S", + alhActionCallback, (XtPointer)MENU_ACTION_MODIFY_MASK, (MenuItem *)NULL, 0 }, + { "Beep Severity ...", ToggleButtonGadgetClass, 'B', "CtrlB", "Ctrl+B", + alhActionCallback, (XtPointer)MENU_ACTION_BEEPSEVR, (MenuItem *)NULL, 0 }, + { "NoAck for One Hour ...", ToggleButtonGadgetClass, 'N', "CtrlN", "Ctrl+N", + alhActionCallback, (XtPointer)MENU_ACTION_NOACKTIMER, (MenuItem *)NULL, 0 }, + {NULL}, + }; + /* Albert Kagarmanov new */ +#ifndef WIN32 + static MenuItem setup_broadcast_mess_menu[] = { + { "Common Message", PushButtonGadgetClass, 'C', NULL, NULL, + messBroadcast, (XtPointer)0, (MenuItem *)NULL, 0 }, + { "Stop Logging Message", PushButtonGadgetClass, 'S', NULL, NULL, + messBroadcast, (XtPointer)1, (MenuItem *)NULL, 0 }, + { "Reload", PushButtonGadgetClass, 'R', NULL, NULL, + messBroadcast, (XtPointer)2, (MenuItem *)NULL, 0 }, + + { "About", PushButtonGadgetClass, 'H', NULL, NULL, + helpMessBroadcast, (XtPointer)0, (MenuItem *)NULL, 0 }, + {NULL}, + }; + +#endif +/* end Albert Kagarmanov new */ +/* ******************************************** Albert1 : ************************************ */ +static MenuItem action_menuNew[] = { + { "Acknowledge Alarm", PushButtonGadgetClass, 'A', "CtrlA", "Ctrl+A", + alhActionCallback, (XtPointer)MENU_ACTION_ACK, (MenuItem *)NULL, 0 }, + { "Display Guidance", PushButtonGadgetClass, 'G', "CtrlG", "Ctrl+G", + alhActionCallback, (XtPointer)MENU_ACTION_GUIDANCE, (MenuItem *)NULL, 0 }, + { "Start Related Process", PushButtonGadgetClass, 'P', "CtrlP", "Ctrl+P", + alhActionCallback, (XtPointer)MENU_ACTION_PROCESS, (MenuItem *)NULL, 0 }, + { "Force Process Variable ...", ToggleButtonGadgetClass, 'V', "CtrlV", "Ctrl+V", + alhActionCallback, (XtPointer)MENU_ACTION_FORCEPV, (MenuItem *)NULL, 0 }, + { "Force Mask ...", ToggleButtonGadgetClass, 'M',"CtrlM", "Ctrl+M", + alhActionCallback, (XtPointer)MENU_ACTION_FORCE_MASK, (MenuItem *)NULL, 0 }, + { "Modify Mask Settings ...", ToggleButtonGadgetClass, 'S', "CtrlS", "Ctrl+S", + alhActionCallback, (XtPointer)MENU_ACTION_MODIFY_MASK, (MenuItem *)NULL, 0 }, + { "Beep Severity ...", ToggleButtonGadgetClass, 'B', "CtrlB", "Ctrl+B", + alhActionCallback, (XtPointer)MENU_ACTION_BEEPSEVR, (MenuItem *)NULL, 0 }, + { "NoAck for One Hour ...", ToggleButtonGadgetClass, 'N', "CtrlN", "Ctrl+N", + alhActionCallback, (XtPointer)MENU_ACTION_NOACKTIMER, (MenuItem *)NULL, 0 }, + /* Albert1 For MESSAGE BROADCAST: */ +#ifndef WIN32 + { "Send Message ...", PushButtonGadgetClass, 'B', "CtrlB", "Ctrl+B", + 0, 0, (MenuItem *)setup_broadcast_mess_menu, 0 }, +#endif + {NULL}, + }; +/* ******************************************** End Albert1 ********************************** */ + + static MenuItem view_menu[] = { + { "Expand One Level", PushButtonGadgetClass, 'L', "Noneplus", "+", + alhViewCallback, (XtPointer)MENU_VIEW_EXPANDCOLLAPSE1, (MenuItem *)NULL, 0 }, + { "Expand Branch", PushButtonGadgetClass, 'B', "Noneasterisk", "*", + alhViewCallback, (XtPointer)MENU_VIEW_EXPANDBRANCH, (MenuItem *)NULL, 0 }, + { "Expand All", PushButtonGadgetClass, 'A', "Ctrlasterisk", "Ctrl+*", + alhViewCallback, (XtPointer)MENU_VIEW_EXPANDALL, (MenuItem *)NULL, 0 }, + { "Collapse Branch", PushButtonGadgetClass, 'C', "Noneminus", "-", + alhViewCallback, (XtPointer)MENU_VIEW_COLLAPSEBRANCH, (MenuItem *)NULL, 0 }, + { "", SeparatorGadgetClass, '\0', NULL, NULL, + NULL, NULL, (MenuItem *)NULL, 0 }, + { "Current Alarm History Window", ToggleButtonGadgetClass, 'H', NULL, NULL, + alhViewCallback, (XtPointer)MENU_VIEW_CURRENT, (MenuItem *)NULL, 0 }, + { "Configuration File Window", ToggleButtonGadgetClass, 'f', NULL, NULL, + alhViewCallback, (XtPointer)MENU_VIEW_CONFIG, (MenuItem *)NULL, 0 }, +#ifdef CMLOG + { "Start CMLOG Log Browser", PushButtonGadgetClass, 's', NULL, NULL, + alhViewCallback, (XtPointer)MENU_VIEW_CMLOG, (MenuItem *)NULL, 0 }, +#endif + { "Alarm Log File Window", ToggleButtonGadgetClass, 'r', NULL, NULL, + alhViewCallback, (XtPointer)MENU_VIEW_ALARMLOG, (MenuItem *)NULL, 0 }, + { "Browser For Alarm Log", ToggleButtonGadgetClass, 's', NULL, NULL, + alhViewBrowserCallback, (XtPointer)MENU_VIEW_ALARMLOG, (MenuItem *)NULL, 0 }, + { "Operation Log File Window", ToggleButtonGadgetClass, 'O', NULL, NULL, + alhViewCallback, (XtPointer)MENU_VIEW_OPMOD, (MenuItem *)NULL, 0 }, + { "Browser For Operation Log", ToggleButtonGadgetClass, 'e', NULL, NULL, + alhViewBrowserCallback, (XtPointer)MENU_VIEW_OPMOD, (MenuItem *)NULL, 0 }, + { "Group/Channel Properties Window", ToggleButtonGadgetClass, 'W', NULL, NULL, + alhViewCallback, (XtPointer)MENU_VIEW_PROPERTIES, (MenuItem *)NULL, 0 }, + + {NULL}, + }; + + static MenuItem setup_beep_menu[] = { + { "Minor", PushButtonGadgetClass, 'M', NULL, NULL, + alhSetupCallback, (XtPointer)MENU_SETUP_BEEP_MINOR, (MenuItem *)NULL, 0 }, + { "Major", PushButtonGadgetClass, 'A', NULL, NULL, + alhSetupCallback, (XtPointer)MENU_SETUP_BEEP_MAJOR, (MenuItem *)NULL, 0 }, + { "Invalid", PushButtonGadgetClass, 'V', NULL, NULL, + alhSetupCallback, (XtPointer)MENU_SETUP_BEEP_INVALID, (MenuItem *)NULL, 0 }, + {NULL}, + }; + + static MenuItem setup_filter_menu[] = { + { "No filter", PushButtonGadgetClass, 'N', NULL, NULL, + alhSetupCallback, (XtPointer)MENU_SETUP_FILTER_NONE, (MenuItem *)NULL, 0 }, + { "Active Alarms Only", PushButtonGadgetClass, 'A', NULL, NULL, + alhSetupCallback, (XtPointer)MENU_SETUP_FILTER_ACTIVE, (MenuItem *)NULL, 0 }, + { "Unacknowledged Alarms Only", PushButtonGadgetClass, 'U', NULL, NULL, + alhSetupCallback, (XtPointer)MENU_SETUP_FILTER_UNACK, (MenuItem *)NULL, 0 }, + {NULL}, + }; + + static MenuItem setup_menu[] = { + { "Display Filter...", PushButtonGadgetClass, 'F', NULL, NULL, + 0, 0, (MenuItem *)setup_filter_menu, 0 }, + { "ALH Beep Severity...", PushButtonGadgetClass, 'B', NULL, NULL, + 0, 0, (MenuItem *)setup_beep_menu, 0 }, +#ifdef AUDIO_BEEP + { "Audio Setup...", ToggleButtonGadgetClass, 'D', NULL, NULL, + alhAudioSetupCallback, NULL, (MenuItem *)NULL, 0 }, +#endif + { "Silence Forever", ToggleButtonGadgetClass, 'S', NULL, NULL, + alhSetupCallback, (XtPointer)MENU_SETUP_SILENCE_FOREVER,(MenuItem *)NULL, 0 }, + { "New Alarm Log File Name...", PushButtonGadgetClass, 'L', NULL, NULL, + alhSetupCallback, (XtPointer)MENU_SETUP_ALARMLOG, (MenuItem *)NULL, 0 }, + { "New Oper. Log File Name...", PushButtonGadgetClass, 'O', NULL, NULL, + alhSetupCallback, (XtPointer)MENU_SETUP_OPMOD, (MenuItem *)NULL, 0 }, + {NULL}, + }; + + static MenuItem help_menu[] = { + { "Help", PushButtonGadgetClass, 'H', "CtrlH", "Ctrl+H", + alhHelpCallback, (XtPointer)MENU_HELP_HELP, (MenuItem *)NULL, 0 }, + { "About ALH", PushButtonGadgetClass, 'A', NULL, NULL, + alhHelpCallback, (XtPointer)MENU_HELP_ABOUT, (MenuItem *)NULL, 0 }, + {NULL}, + }; + + Widget menubar,widget; + + /* Set "Silence Forever" toggleButton initial state */ + setup_menu[2].initial_state = psetup.silenceForever; + + menubar = XmCreateMenuBar(parent, "menubar", NULL, 0); + + widget = buildPulldownMenu(menubar, "File", 'F', TRUE, file_menu, user_data); + if(!_message_broadcast_flag) /* Albert1 */ + widget = buildPulldownMenu(menubar, "Action", 'A', TRUE, action_menu, user_data); + else + widget = buildPulldownMenu(menubar, "Action", 'A', TRUE, action_menuNew, user_data); + + widget = buildPulldownMenu(menubar, "View", 'V', TRUE, view_menu, user_data); + + widget = buildPulldownMenu(menubar, "Setup", 'S', TRUE, setup_menu, user_data); + + widget = buildPulldownMenu(menubar, "Help", 'H', TRUE, help_menu, user_data); + + + + /* Make sure Help on MenuBar item is right adjusted */ + XtVaSetValues(menubar, XmNtopAttachment, XmATTACH_FORM, NULL); + XtVaSetValues(menubar, XmNrightAttachment, XmATTACH_FORM, NULL); + XtVaSetValues(menubar, XmNleftAttachment, XmATTACH_FORM, NULL); + XtVaSetValues(menubar, XmNmenuHelpWidget, widget, NULL); + + XtManageChild(menubar); + + return(menubar); +} + + +/****************************************************** + alhFileCallback +******************************************************/ +static void alhFileCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + ALINK *area; + int item=(long)calldata; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + switch (item){ + + case MENU_FILE_OPEN: + + /* New Name for Config File */ + + /* Display the config_changed warning dialog */ + if (area->changed){ + createActionDialog(area->form_main,XmDIALOG_WARNING, + "Config file settings have Changed. Do you wish to continue?", + (XtCallbackProc)alhFileCallback, + (XtPointer)MENU_FILE_OPEN_OK, (XtPointer)area); + break; + } + area->managed = FALSE; + createFileDialog(area->form_main, + (void *)fileSetupCallback, (XtPointer)FILE_CONFIG, + (void *)fileCancelCallback,(XtPointer)area, + (XtPointer)area, + "Alarm Configuration File",CONFIG_PATTERN,psetup.configDir); + break; + + case MENU_FILE_OPEN_OK: + + area->managed = FALSE; + createFileDialog(area->form_main, + (void *)fileSetupCallback, (XtPointer)FILE_CONFIG, + (void *)fileCancelCallback,(XtPointer)area, + (XtPointer)area, + "Alarm Configuration File",CONFIG_PATTERN,psetup.configDir); + break; + + case MENU_FILE_SAVEAS: + /* New Name for Save Config File */ + + createFileDialog(area->form_main, + (void *)fileSetupCallback, (XtPointer)FILE_SAVEAS, + (void *)XtUnmanageChild,(XtPointer)0, + (XtPointer)area, + "Save Alarm Configuration File",CONFIG_PATTERN,psetup.configDir); + break; + + case MENU_FILE_CLOSE: + + /* "Close" was selected. */ + if (_main_window_flag) + exit_quit(area->toplevel,(XtPointer)area,(XtPointer)area); + else + unmapArea_callback(area->toplevel,area->form_main,(XmAnyCallbackStruct *)cbs); + break; + + case MENU_FILE_QUIT: + + createActionDialog(area->toplevel,XmDIALOG_WARNING, + "Exit Alarm Handler?",(XtCallbackProc)exit_quit, + (XtPointer)area, (XtPointer)area); + break; + } +} + + +/****************************************************** + alhActionCallback +******************************************************/ + +static void alhActionCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + int item=(long)calldata; + ALINK *area; + Widget parent; + GCLINK *link; + struct anyLine *line; + WLINE *wline; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + switch (item){ + + case MENU_ACTION_ACK: + + /* Acknowledge Alarm */ + link = (GCLINK *)area->selectionLink; + + if (link){ + line = (struct anyLine *)link->lineTreeW; + if (line && line->pwindow == (void *)area->selectionWindow ){ + + ack_callback(widget,line,(XmAnyCallbackStruct *)cbs); + } + else { + line = (struct anyLine *)link->lineGroupW; + if (line && line->pwindow == (void *)area->selectionWindow ){ + ack_callback(widget,line,(XmAnyCallbackStruct *)cbs); + } + } + } else { + createDialog(area->form_main,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + } + break; + + case MENU_ACTION_GUIDANCE: + + /* Display Guidance */ + link = (GCLINK *)area->selectionLink; + line = (struct anyLine *)link->lineTreeW; + if (! line || line->pwindow != (void *)area->selectionWindow ) + line = (struct anyLine *)link->lineGroupW; + if (line){ + wline=(WLINE *)line->wline; + guidanceCallback(wline->guidance,(GCLINK *)link,(XmAnyCallbackStruct *) cbs); + } + else { + createDialog(area->form_main,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + } + break; + + case MENU_ACTION_PROCESS: + + /* Start Related Process */ + link = (GCLINK *)area->selectionLink; + if (link){ + if (alProcessExists(link)){ + relatedProcess_callback(widget,link, cbs); + } else { + if (((GCLINK *)link)->pgcData->alias){ + createDialog(area->form_main,XmDIALOG_WARNING,"No related process for ", + link->pgcData->alias); + } else { + createDialog(area->form_main,XmDIALOG_WARNING,"No related process for ", + link->pgcData->name); + } + } + } else { + createDialog(area->form_main,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + } + break; + + + case MENU_ACTION_FORCEPV: + + if (area->selectionLink) { + forcePVShowDialog(area, widget); + } else { + parent = area->form_main; + createDialog(parent,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + } + break; + + case MENU_ACTION_FORCE_MASK: + + if (area->selectionLink) { + forceMaskShowDialog(area, widget); + } else { + parent = area->form_main; + createDialog(parent,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + } + break; + + case MENU_ACTION_MODIFY_MASK: + + if (area->selectionLink) { + maskShowDialog(area, widget); + } else { + parent = area->form_main; + createDialog(parent,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + } + break; + + case MENU_ACTION_BEEPSEVR: + + if (area->selectionLink) { + beepSevrShowDialog(area, widget); + } else { + parent = area->form_main; + createDialog(parent,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + } + break; + + case MENU_ACTION_NOACKTIMER: + + if (area->selectionLink) { + noAckShowDialog(area, widget); + } else { + parent = area->form_main; + createDialog(parent,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + } + break; + + } +} + + +/****************************************************** + alhViewCallback +******************************************************/ +static void alhViewCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + int item=(long)calldata; + ALINK *area; + void *link; + struct subWindow *treeWindow; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + treeWindow = (struct subWindow *)area->treeWindow; + + switch (item){ + + case MENU_VIEW_EXPANDCOLLAPSE1: + + /* Expand 1 level */ + link = treeWindow->selectionLink; + if (link) displayNewViewTree(area,link,EXPANDCOLLAPSE1); + else createDialog(area->form_main,XmDIALOG_WARNING,"Please select an alarm group first."," "); + break; + + case MENU_VIEW_EXPANDBRANCH: + + /* Expand Branch */ + link = treeWindow->selectionLink; + if (link )displayNewViewTree(area,link,EXPAND); + else createDialog(area->form_main,XmDIALOG_WARNING,"Please select an alarm group first."," "); + break; + + case MENU_VIEW_EXPANDALL: + + /* Expand all */ + displayNewViewTree(area,(GLINK *)sllFirst(area->pmainGroup),EXPAND); + break; + + case MENU_VIEW_COLLAPSEBRANCH: + + /* Collapse branch */ + link = treeWindow->selectionLink; + if (link )displayNewViewTree(area,link,COLLAPSE); + else createDialog(area->form_main,XmDIALOG_WARNING,"Please select an alarm group first."," "); + break; + + case MENU_VIEW_CURRENT: + + /* Display Current Alarm History */ + currentAlarmHistoryWindow(area,widget); + break; + + case MENU_VIEW_CONFIG: + + /* Display Alarm Configuration File */ + fileViewWindow(area->form_main,CONFIG_FILE,widget); + break; + + case MENU_VIEW_ALARMLOG: + + /* Display Alarm Log File */ + fileViewWindow(area->form_main,ALARM_FILE,widget); + break; + + case MENU_VIEW_OPMOD: + + /* Display Operation Log File */ + fileViewWindow(area->form_main,OPMOD_FILE,widget); + break; +#ifdef CMLOG + case MENU_VIEW_CMLOG: + + /* Start CMLOG Browser */ + awCMLOGstartBrowser(); + break; +#endif + case MENU_VIEW_PROPERTIES: + + /* Display Group/Chan Properties */ + propShowDialog(area, widget); + break; + + } +} + +/****************************************************** + FileSelect for AlhView. Albert +******************************************************/ +static void alhViewBrowserCallback(Widget widget,XtPointer item,XtPointer cbs) +{ + ALINK *area; + Widget dialog; + XmString Xpattern,Xtitle,Xcurrentdir; + int ch = (long) item; + switch ( ch ) + { + case MENU_VIEW_ALARMLOG: + Xtitle=XmStringCreateSimple("Alarm Log File"); + Xpattern = XmStringCreateSimple(psetup.logFile); + Xcurrentdir = XmStringCreateSimple(psetup.logDir); + break; + + case MENU_VIEW_OPMOD: + Xtitle=XmStringCreateSimple("Operator File"); + Xpattern = XmStringCreateSimple(psetup.opModFile); + Xcurrentdir = XmStringCreateSimple(psetup.logDir); /* Albert1 ???? */ + break; + + default: + perror("bad item"); + return; + } + + XtVaGetValues(widget, XmNuserData, &area, NULL); + dialog=XmCreateFileSelectionDialog(area->form_main,"dialog",NULL,0); + switch ( ch ) + { + case MENU_VIEW_ALARMLOG: + XtVaSetValues(dialog,XmNuserData,ALARM_FILE,NULL); + break; + case MENU_VIEW_OPMOD: + XtVaSetValues(dialog,XmNuserData,OPMOD_FILE,NULL); + break; + + } + XtAddCallback(dialog,XmNokCallback,(XtCallbackProc)browserFBSDialogCbOk,widget); + XtAddCallback(dialog,XmNcancelCallback,(XtCallbackProc)browserFBSDialogCbCancel,NULL); + XtUnmanageChild(XmFileSelectionBoxGetChild(dialog, + XmDIALOG_HELP_BUTTON)); + + XtVaSetValues(dialog, + XmNdirectory, Xcurrentdir, + XmNdialogTitle, Xtitle, + XmNdirMask, Xpattern, + XmNfileTypeMask, XmFILE_REGULAR, + (XtPointer)NULL); + XtManageChild(dialog); + XmStringFree(Xpattern); + XmStringFree(Xtitle); +} + +/****************************************************** + browserFBSDialogCbCancel +******************************************************/ +static void browserFBSDialogCbCancel(Widget w,int client_data, +XmSelectionBoxCallbackStruct *call_data) +{ + XtUnmanageChild(w); +} + +/****************************************************** + browserFBSDialogCbOk +******************************************************/ +static void browserFBSDialogCbOk(Widget w,Widget wdgt, +XmSelectionBoxCallbackStruct *call_data) +{ + ALINK *area; + char *s; + int fileType; + XmStringGetLtoR(call_data->value,XmSTRING_DEFAULT_CHARSET,&s); + strcpy(FS_filename,s); + XtFree(s); + XtVaGetValues(w, XmNuserData, &fileType, NULL); + XtVaGetValues(wdgt, XmNuserData, &area, NULL); + browser_fileViewWindow(area->form_main,fileType,wdgt); /* Albert1 */ + XtUnmanageChild(w); +} + +#ifndef WIN32 +struct messBroadcastData +{ +int type; +ALINK *area; +} +messBroadcastData; + + +/****************************************************** +Send Message widget +******************************************************/ +static void messBroadcast(Widget widget,XtPointer item,XtPointer cbs) /* Albert1 */ +{ + Widget dialog, text_w; + ALINK *area; + static struct messBroadcastData mBD; + int itemi = (long) item; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + if(amIsender) + { + createDialog(area->form_main,XmDIALOG_INFORMATION, + "You send some message before. \n" "\n" + "Please wait a few seconds \n",""); + return; + } + if ( lockf(messBroadcastDeskriptor, F_TLOCK, 0L) < 0 ) { + if ((errno == EAGAIN || errno == EACCES )) { + if(DEBUG) fprintf(stderr,"file is busy;Deskriptor=%d\n",messBroadcastDeskriptor); + createDialog(area->form_main,XmDIALOG_INFORMATION, + "Some other operator type a message. \n" "\n" + "Please wait a few seconds \n",""); + return; + } + else { + perror("lockf Error!!!!"); /* Albert1 exit ?????? */ + } + } + else + { + if(DEBUG) fprintf(stderr,"file is free;Deskriptor=%d\n",messBroadcastDeskriptor); + + dialog = XmCreatePromptDialog(area->form_main, "dialog", NULL, 0); + XtVaSetValues(dialog,XtVaTypedArg, XmNselectionLabelString, XmRString, + "Type message (See help for detail):", 40,NULL); + + XtAddCallback(dialog, XmNcancelCallback,(XtCallbackProc)cancelMessBroadcast, NULL); + XtAddCallback(dialog, XmNhelpCallback,(XtCallbackProc)helpMessBroadcast, NULL); + text_w = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT); + if(itemi == 1) + { + XtVaSetValues(text_w, XmNvalue,"0 min no write to LOG file", NULL); + } + if(itemi == 2) + { + if(DEBUG) fprintf(stderr,"second item\n"); + XtVaSetValues(text_w, XmNvalue,"Reload config. Reason:", NULL); + } + + mBD.area =area; + mBD.type =itemi; + + XtVaSetValues(dialog,XmNuserData,&mBD,NULL); + XtAddCallback(dialog, XmNokCallback,(XtCallbackProc)writeMessBroadcast, text_w); + XtManageChild(dialog); + + } +} + +ALINK *ar; + +static void writeMessBroadcast(Widget dialog, Widget text_w) +{ +FILE *fp; +time_t timeID,time_tmp; +void messBroadcastFileUnlock(); +static char string[256]; +char *MessString; +char *blank; + +int notsave_time; +static char buff[500]; +static struct messBroadcastData *mBDpt; + +int type; + + memset(string,0,256); + XtVaGetValues(dialog, XmNuserData,&mBDpt, NULL); + + type=mBDpt->type; + if (( type <0) && ( type >2)) return; + + ar= mBDpt->area; + + if ( (fp=fopen(messBroadcastInfoFileName,"w")) == NULL ) + { + createDialog(ar->form_main,XmDIALOG_INFORMATION,"can't open ",messBroadcastInfoFileName); + lockf(messBroadcastDeskriptor, F_ULOCK, 0L); + return; + } + + + timeID=time(0L); + time_tmp=timeID; + + MessString = XmTextFieldGetString(text_w); + if(type == 0) {strcpy(string,"0 "); strcat(string,MessString);} + else if (type == 1) strcpy(string,MessString); + else if (type == 2) {strcpy(string,reloadMBString);strcat(string,MessString);} + + if( (blank=strchr(string,' ')) == NULL ) + { + createDialog(ar->form_main,XmDIALOG_INFORMATION,"Wrong format"," "); + lockf(messBroadcastDeskriptor, F_ULOCK, 0L); + return; + } + *blank=0; + blank++; + notsave_time=atoi(string);/*problem to distinguish illegal number and 0-number:*/ + if(notsave_time==0) + { + if(! (string[0] - '0'== 0)&&(string[1] - ' '== 0) ) + { + if(DEBUG) printf("Real ! zerro=%s\n",string); + notsave_time =-1; + } + else {if(DEBUG) printf("Real zerro=%s\n",string); } + } + + if( (notsave_time < 0) || (notsave_time > max_not_save_time) ) + { + createDialog(ar->form_main,XmDIALOG_INFORMATION,"time so big!!!"," "); + lockf(messBroadcastDeskriptor, F_ULOCK, 0L); + return; + } + + if(notsave_time != 0) + { + sprintf(buff,"%d %s %s\nDate is %sFROM: User=%s [%s] host=%s display=%s",notsave_time, + rebootString, blank,ctime(&time_tmp),userID.loginid, + userID.real_world_name,userID.myhostname,userID.displayName); + } + else + { + sprintf(buff,"%s\nDate is %sFROM: User=%s [%s] host=%s display=%s", + blank,ctime(&time_tmp),userID.loginid, + userID.real_world_name,userID.myhostname,userID.displayName); + } + + fprintf(fp,"%ld\n%s",timeID,buff); + createDialog(ar->form_main,XmDIALOG_MESSAGE,"Broadcast Message: \n""\n""\n",buff); + + fclose(fp); + XtFree(string); + amIsender=1; + XtAppAddTimeOut(appContext,messBroadcastLockDelay,messBroadcastFileUnlock,NULL); + +} + +static void messBroadcastFileUnlock() +{ + FILE *fp; + if(DEBUG) fprintf(stderr,"delete messBroadcastInfoFileName...\n"); + if ( (fp=fopen(messBroadcastInfoFileName,"w")) == NULL ) + { + perror("Loop:can't open messBroadcastInfoFileName!!!!"); + } + if (fp) fclose (fp); + amIsender=0; + lockf(messBroadcastDeskriptor, F_ULOCK, 0L); +} + +static void helpMessBroadcast(Widget w,XtPointer item,XtPointer cbs) +{ +createDialog(XtParent(w),XmDIALOG_INFORMATION, +"This message will be send all other operators\n" +"which work with the same alh configuration.\n" +"\n" +"1) If you choose 'Stop Logging Message'\n" +" first symbol must be a number:\n" +"\n" +" ''time_in_min ''any other text '' ''\n" +"\n" +" After that ALH will NOT save alarms during 'time_in_min'\n" +"\n" +" It's very usefull before rebooting IOC \n" +" (all other will know about that) \n" +" or if you don't like save alarms during this short\n" +" (no more than 10 min) time.\n" +"\n" +"\n" +"\n" +"2) If you choose 'Reload'-part all alh-proceses (including your current process)\n" +"will reload config file.\n" +"\n" +"\n" +"\n" +"3) If you choose 'Common Message'-part\n" +" it's mean any other information messages without stop logging.\n" +"\n" +" You can use it for any other communications\n" +" (like Hi All!, Need Help!,No meeting today!, ...)", +""); +} + +static void cancelMessBroadcast(Widget w) +{ +XtUnmanageChild(w); + lockf(messBroadcastDeskriptor, F_ULOCK, 0L); +} + +#endif + +/****************************************************** + alhSetupCallback +******************************************************/ +static void alhSetupCallback( Widget widget, XtPointer calldata, XtPointer cbs) +{ + int item=(long)calldata; + ALINK *area; + + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + switch (item){ + + case MENU_SETUP_FILTER_NONE: + area->viewFilter = alFilterAll; + createConfigDisplay(area,EXPANDCOLLAPSE1); + break; + + case MENU_SETUP_FILTER_ACTIVE: + area->viewFilter = alFilterAlarmsOnly; + createConfigDisplay(area,EXPANDCOLLAPSE1); + break; + + case MENU_SETUP_FILTER_UNACK: + area->viewFilter = alFilterUnackAlarmsOnly; + createConfigDisplay(area,EXPANDCOLLAPSE1); + break; + + case MENU_SETUP_BEEP_MINOR: + + psetup.beepSevr = MINOR_ALARM; + changeBeepSeverityText(area); + break; + + case MENU_SETUP_BEEP_MAJOR: + + psetup.beepSevr = MAJOR_ALARM; + changeBeepSeverityText(area); + break; + + case MENU_SETUP_BEEP_INVALID: + + psetup.beepSevr = INVALID_ALARM; + changeBeepSeverityText(area); + break; + + case MENU_SETUP_SILENCE_FOREVER: + + silenceForeverChangeState(area); + break; + + case MENU_SETUP_ALARMLOG: + + /* New Name for Alarm Log File */ + createFileDialog(area->form_main, + (void *)fileSetupCallback,(XtPointer)FILE_ALARMLOG, + (void *)XtUnmanageChild,(XtPointer)0, + (XtPointer)area, + "Alarm Log File",ALARMLOG_PATTERN,psetup.logDir); + break; + + case MENU_SETUP_OPMOD: + + /* New Name for Operations Log File */ + createFileDialog(area->form_main, + (void *)fileSetupCallback,(XtPointer)FILE_OPMOD, + (void *)XtUnmanageChild,(XtPointer)0, + (XtPointer)area, + "Operator Modification File", OPMOD_PATTERN,psetup.logDir); + break; + + } +} + + +/****************************************************** + alhHelpCallback +******************************************************/ +static void alhHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + int item=(long)calldata; + ALINK *area; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + switch (item){ + +#ifdef ALH_HELP_URL + case MENU_HELP_HELP: + + callBrowser(ALH_HELP_URL); + break; +#endif + + case MENU_HELP_ABOUT: + + createDialog(area->form_main,XmDIALOG_INFORMATION, + "\nAlarm Handler\n\n" ALH_CREDITS_STRING ,alhVersionString); + + break; + + default: + + createDialog(area->form_main,XmDIALOG_INFORMATION, + "Help is not available in this release."," "); + break; + } +} + + +/****************************************************** + awRowWidgets +******************************************************/ +void awRowWidgets(struct anyLine *line,void *area) +{ + + void *subWindow; + XmString str; + WLINE *wline; + void *link; + GLINK *glink; + Position nextX; + Dimension width; + Widget parent; + Pixel backgroundColor; + + subWindow=line->pwindow; + parent = ((struct subWindow *)subWindow)->drawing_area; + wline=(WLINE *)line->wline; + link = line->link; + glink = (GLINK *)line->link; + + /* create row widgets */ + if (wline->row_widget == NULL) { + + + wline->row_widget = XtVaCreateWidget(NULL, + xmDrawingAreaWidgetClass, parent, + XmNy, calcRowYValue(subWindow,line->lineNo), + XmNnavigationType, XmNONE, + XmNorientation, XmHORIZONTAL, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + (XtPointer)NULL); + nextX = 0; + + XtVaGetValues(parent,XmNbackground,&backgroundColor,NULL); + XtVaSetValues(wline->row_widget,XmNbackground,backgroundColor,NULL); + + if ( isTreeWindow(area,subWindow) && line->linkType == GROUP) { + if ( glink->pgroupData->treeSym) { + str = XmStringCreateSimple(glink->pgroupData->treeSym); + wline->treeSym = XtVaCreateManagedWidget("treeSym", + xmLabelGadgetClass, wline->row_widget, + XmNlabelString, str, + XmNmarginHeight, 0, + NULL); + XmStringFree(str); + XtVaGetValues(wline->treeSym,XmNwidth,&width,NULL); + nextX = width + 3; + } + } + + str = XmStringCreateSimple(bg_char[line->unackSevr]); + wline->ack = XtVaCreateManagedWidget("ack", + xmPushButtonWidgetClass, wline->row_widget, + XmNmarginHeight, 0, + XmNlabelString, str, + XmNsensitive, FALSE, + XmNuserData, (XtPointer)area, + XmNx, nextX, + NULL); + XmStringFree(str); + XtAddCallback(wline->ack, XmNactivateCallback, + (XtCallbackProc)ack_callback, line); + XtVaGetValues(wline->ack,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + + str = XmStringCreateSimple(bg_char[line->curSevr]); + wline->sevr = XtVaCreateManagedWidget("sevr", + xmLabelWidgetClass, wline->row_widget, + XmNlabelString, str, + XmNx, nextX, + XmNy, 2, + NULL); + XmStringFree(str); + XtVaGetValues(wline->sevr,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + /* load actions once */ + if ( g_transInit ) { + g_transInit = 0; + g_parsedTrans = XtParseTranslationTable( g_dragTrans ); + XtAppAddActions( appContext, g_dragActions, XtNumber(g_dragActions) ); + } + + str = XmStringCreateSimple(line->alias); + wline->name = XtVaCreateManagedWidget("pushButtonName", + xmPushButtonWidgetClass, wline->row_widget, + XmNmarginHeight, 0, + XmNlabelString, str, + XmNuserData, (XtPointer) line, + XmNx, nextX, + NULL); + XmStringFree(str); + XtOverrideTranslations( wline->name, g_parsedTrans ); + if (line->linkType == CHANNEL) { +#if XmVersion && XmVersion >= 1002 + XmChangeColor(wline->name,channel_bg_pixel); +#else + XtVaSetValues(wline->name,XmNbackground,channel_bg_pixel,NULL); +#endif + } + if ( isTreeWindow(area,subWindow) ) { + XtAddCallback(wline->name, XmNactivateCallback, + (XtCallbackProc)nameTreeW_callback, line); + } else { + XtAddCallback(wline->name, XmNactivateCallback, + (XtCallbackProc)nameGroupW_callback, line); + } + XtVaGetValues(wline->name,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + wline->arrow = XtVaCreateWidget("pushButtonArrow", + xmArrowButtonWidgetClass, wline->row_widget, + XmNshadowThickness, 0, + XmNarrowDirection, XmARROW_RIGHT, + XmNuserData, (XtPointer)area, + XmNx, nextX, + XmNy, 2, + XmNbackground, backgroundColor, + (XtPointer)NULL); + if (line->linkType == GROUP && sllFirst(&(glink->subGroupList))){ + XtManageChild(wline->arrow); + if ( isTreeWindow(area,subWindow) ) { + XtAddCallback(wline->arrow, XmNactivateCallback, + (XtCallbackProc)arrowTreeW_callback, link); + } else { + XtAddCallback(wline->arrow, XmNactivateCallback, + (XtCallbackProc)arrowGroupW_callback, link); + } + XtVaGetValues(wline->arrow,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + } + + wline->guidance = XtVaCreateWidget("G", + xmPushButtonWidgetClass, wline->row_widget, + XmNmarginHeight, 0, + XmNuserData, (XtPointer)line->alias, + XmNx, nextX, + XmNbackground, backgroundColor, + NULL); + + if (guidanceExists(link)) { + XtManageChild(wline->guidance); + XtAddCallback(wline->guidance, XmNactivateCallback, + (XtCallbackProc)guidanceCallback, link); + XtVaGetValues(wline->guidance,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + } + + wline->process = XtVaCreateWidget("P", + xmPushButtonWidgetClass, wline->row_widget, + XmNmarginHeight, 0, + XmNuserData, (XtPointer)area, + XmNx, nextX, + XmNbackground, backgroundColor, + NULL); + + if (alProcessExists(link) ){ + XtManageChild(wline->process); + XtAddCallback(wline->process, XmNactivateCallback, + (XtCallbackProc)relatedProcess_callback, link); + XtVaGetValues(wline->process,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + } + + str = XmStringCreateSimple(line->mask); + wline->mask = XtVaCreateManagedWidget("mask", + xmLabelWidgetClass, wline->row_widget, + XmNlabelString, str, + XmNx, nextX, + XmNy, 2, + XmNbackground, backgroundColor, + NULL); + XmStringFree(str); + XtVaGetValues(wline->mask,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + str = XmStringCreateSimple(line->highestBeepSevrString); + wline->highestbeepsevr = XtVaCreateManagedWidget("highestbeepsevr", + xmLabelWidgetClass, wline->row_widget, + XmNlabelString, str, + XmNx, nextX, + XmNy, 2, + XmNbackground, backgroundColor, + NULL); + XmStringFree(str); + XtVaGetValues(wline->highestbeepsevr,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + str = XmStringCreateSimple(line->message); + wline->message = XtVaCreateManagedWidget("message", + xmLabelWidgetClass, wline->row_widget, + XmNlabelString, str, + XmNx, nextX, + XmNy, 2, + XmNbackground, backgroundColor, + NULL); + XmStringFree(str); + XtVaGetValues(wline->message,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + awUpdateRowWidgets(line); + + XtManageChild(wline->row_widget); + } + + else + + /* else modify existing row widgets */ + { + if ( wline->row_widget && XtIsManaged(wline->row_widget)){ + XtUnmanageChild(wline->row_widget); + } + + nextX = 0; + if ( isTreeWindow(area,subWindow) && line->linkType == GROUP) { + str = XmStringCreateSimple(glink->pgroupData->treeSym); + XtVaSetValues(wline->treeSym, + XmNlabelString, str, + NULL); + XmStringFree(str); + XtVaGetValues(wline->treeSym,XmNwidth,&width,NULL); + nextX = width + 3; + } + + if (line->unackSevr == FALSE) { + XtVaSetValues(wline->ack, + XmNsensitive, FALSE, + NULL); + } + else { + XtVaSetValues(wline->ack, + XmNsensitive, TRUE, + NULL); + } + + XtVaSetValues(wline->ack,XmNx,nextX,NULL); + XtRemoveAllCallbacks(wline->ack, XmNactivateCallback); + XtAddCallback(wline->ack, XmNactivateCallback, + (XtCallbackProc)ack_callback, line); + XtVaGetValues(wline->ack,XmNwidth,&width,NULL); + nextX = nextX + width +3; + + + XtVaSetValues(wline->sevr,XmNx,nextX,NULL); + XtVaGetValues(wline->sevr,XmNwidth,&width,NULL); + nextX = nextX + width +3; + + str = XmStringCreateSimple(line->alias); + XtVaSetValues(wline->name, + XmNlabelString, str, + XmNx, nextX, + NULL); + XmStringFree(str); + if ( ! isTreeWindow(area,subWindow)) { + if (line->linkType == CHANNEL) { +#if XmVersion && XmVersion >= 1002 + XmChangeColor(wline->name,channel_bg_pixel); +#else + XtVaSetValues(wline->name,XmNbackground,channel_bg_pixel,NULL); +#endif + } + if (line->linkType == GROUP) { +#if XmVersion && XmVersion >= 1002 + XmChangeColor(wline->name,bg_pixel[0]); +#else + XtVaSetValues(wline->name,XmNbackground,bg_pixel[0],NULL); +#endif + } + } + XtRemoveAllCallbacks(wline->name, XmNactivateCallback); + if ( isTreeWindow(area,subWindow) ) { + XtAddCallback(wline->name, XmNactivateCallback, + (XtCallbackProc)nameTreeW_callback, line); + } else { + XtAddCallback(wline->name, XmNactivateCallback, + (XtCallbackProc)nameGroupW_callback, line); + } + XtVaGetValues(wline->name,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + if (XtHasCallbacks(wline->arrow,XmNactivateCallback)) + XtRemoveAllCallbacks(wline->arrow, XmNactivateCallback); + if (line->linkType == GROUP && sllFirst(&(glink->subGroupList))){ + XtVaSetValues(wline->arrow,XmNx,nextX,NULL); + XtManageChild(wline->arrow); + if ( isTreeWindow(area,subWindow) ) { + XtAddCallback(wline->arrow, XmNactivateCallback, + (XtCallbackProc)arrowTreeW_callback, link); + } else { + XtAddCallback(wline->arrow, XmNactivateCallback, + (XtCallbackProc)arrowGroupW_callback, link); + } + XtVaGetValues(wline->arrow,XmNwidth,&width,NULL); + nextX = nextX + width +3; + + } else { + XtUnmanageChild(wline->arrow); + } + + if (XtHasCallbacks(wline->guidance,XmNactivateCallback)) + XtRemoveAllCallbacks(wline->guidance, XmNactivateCallback); + if (guidanceExists(link)) { + XtVaSetValues(wline->guidance,XmNx,nextX,NULL); + XtVaSetValues(wline->guidance,XmNuserData,line->alias,NULL); + XtManageChild(wline->guidance); + XtAddCallback(wline->guidance, XmNactivateCallback, + (XtCallbackProc)guidanceCallback, link); + XtVaGetValues(wline->guidance,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + } else { + XtUnmanageChild(wline->guidance); + } + + if (XtHasCallbacks(wline->process,XmNactivateCallback)) + XtRemoveAllCallbacks(wline->process, XmNactivateCallback); + if (alProcessExists(link) ){ + XtVaSetValues(wline->process,XmNx,nextX,NULL); + XtManageChild(wline->process); + XtAddCallback(wline->process, XmNactivateCallback, + (XtCallbackProc)relatedProcess_callback, link); + XtVaGetValues(wline->process,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + } else { + XtUnmanageChild(wline->process); + } + + XtVaSetValues(wline->mask,XmNx,nextX,NULL); + XtVaGetValues(wline->mask,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + XtVaSetValues(wline->highestbeepsevr,XmNx,nextX,NULL); + XtVaGetValues(wline->highestbeepsevr,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + XtVaSetValues(wline->message,XmNx,nextX,NULL); + XtVaGetValues(wline->message,XmNwidth,&width,NULL); + nextX = nextX + width + 3; + + awUpdateRowWidgets(line); + + XtManageChild(wline->row_widget); + + } + +} + + +/****************************************************** + awUpdateRowWidgets +******************************************************/ +void awUpdateRowWidgets(struct anyLine *line) +{ + XmString str; + WLINE *wline; + Pixel bg; + XmString strOld; + Boolean sensitiveOld; + + wline=(WLINE *)line->wline; + + XtVaGetValues(wline->ack, + XmNbackground, &bg, + XmNlabelString, &strOld, + XmNsensitive, &sensitiveOld, + (XtPointer)NULL); + + if (line->unackSevr == FALSE) { + if (sensitiveOld == TRUE) + XtVaSetValues(wline->ack, + XmNsensitive, FALSE, + NULL); + } + else { + if (sensitiveOld == FALSE) + XtVaSetValues(wline->ack, + XmNsensitive, TRUE, + NULL); + } + str = XmStringCreateSimple(bg_char[line->unackSevr]); + if (!XmStringCompare(str,strOld)) + XtVaSetValues(wline->ack, + XmNlabelString, str, + NULL); + XmStringFree(strOld); + XmStringFree(str); + + if (bg != bg_pixel[line->unackSevr]){ +#if XmVersion && XmVersion >= 1002 + XmChangeColor(wline->ack,bg_pixel[line->unackSevr]); +#else + XtVaSetValues(wline->ack,XmNbackground,bg_pixel[line->unackSevr],NULL); +#endif + } + + XtVaGetValues(wline->sevr, + XmNbackground, &bg, + XmNlabelString, &strOld, + NULL); + + str = XmStringCreateSimple(bg_char[line->curSevr]); + if (!XmStringCompare(str,strOld)) + XtVaSetValues(wline->sevr, + XmNlabelString, str, + NULL); + XmStringFree(str); + XmStringFree(strOld); + + if (bg != bg_pixel[line->curSevr]){ +#if XmVersion && XmVersion >= 1002 + XmChangeColor(wline->sevr,bg_pixel[line->curSevr]); +#else + XtVaSetValues(wline->sevr,XmNbackground,bg_pixel[line->curSevr],NULL); +#endif + } + + XtVaGetValues(wline->mask, + XmNlabelString, &strOld, + NULL); + + str = XmStringCreateSimple(line->mask); + if (!XmStringCompare(str,strOld)) + XtVaSetValues(wline->mask, + XmNlabelString, str, + NULL); + XmStringFree(str); + XmStringFree(strOld); + + XtVaGetValues(wline->message, + XmNlabelString, &strOld, + NULL); + str = XmStringCreateSimple(line->message); + if (!XmStringCompare(str,strOld)) + XtVaSetValues(wline->message, + XmNlabelString, str, + NULL); + XmStringFree(str); + XmStringFree(strOld); + + XtVaGetValues(wline->highestbeepsevr, + XmNlabelString, &strOld, + NULL); + str = XmStringCreateSimple(line->highestBeepSevrString); + if (!XmStringCompare(str,strOld)) + XtVaSetValues(wline->highestbeepsevr, + XmNlabelString, str, + NULL); + XmStringFree(str); + XmStringFree(strOld); + +} + + +/*+************************************************************************** + * + * Function: awCMLOGstartBrowser + * + * Description: Starts the standard Motif CMLOG browser + * + **************************************************************************-*/ + +#ifdef CMLOG +static void awCMLOGstartBrowser (void) +{ + char command[256]; + + switch (fork()) { + /* Error */ + case -1: + perror("Cannot fork() to start CMLOG browser"); + return; + /* Child */ + case 0: + if (psetup.configDir) + sprintf(command, CMLOG_BROWSER" -f %s/"CMLOG_CONFIG" &", psetup.configDir); + else + sprintf(command, CMLOG_BROWSER" -f "CMLOG_CONFIG" &"); + + system(command); + exit(0); + break; + /* Parent */ + default: + break; + } + return; +} +#endif diff --git a/awEdit.c b/awEdit.c new file mode 100644 index 0000000..96be04a --- /dev/null +++ b/awEdit.c @@ -0,0 +1,440 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* awEdit.c */ + +/************************DESCRIPTION*********************************** + This file contains routines for edit functions +**********************************************************************/ + +#include +#include +#include + +#include + +#include "alarm.h" + +#include "alh.h" +#include "line.h" +#include "axSubW.h" +#include "alLib.h" +#include "axArea.h" +#include "sllLib.h" +#include "ax.h" + +#define KEEP 0 +#define ALH_DELETE 1 + +static struct undoInfo { + GCLINK *link; + int linkType; + GCLINK *configLink; + int command; + int delete; +} undoData; + +struct clipInfo { + GCLINK *link; + int linkType; +} clipData = { + 0, 0 }; + + + +/****************************************************** + editUndoSet +******************************************************/ +void editUndoSet(GCLINK *link,int linkType,GCLINK *configLink, +int command,int delete) +{ + /* delete unused configLink group or channel */ + /* + if (delete && link && link != configLink){ + if (undoData.linkType == GROUP) + alRemoveGroup((GLINK *)undoData.link); + else + alRemoveChan((CLINK *)undoData.link); + } + */ + undoData.link = link; + undoData.linkType = linkType; + undoData.configLink = configLink; + undoData.command = command; +} + +/****************************************************** + editUndoGet +******************************************************/ +void editUndoGet(GCLINK **plink,int *plinkType,GCLINK **pconfigLink) +{ + static int undoInit=1; + + if (undoInit) { + undoData.link=NULL; + undoData.linkType=0; + undoData.configLink=NULL; + undoInit =0; + } + *plink = undoData.link; + *plinkType = undoData.linkType; + *pconfigLink = undoData.configLink; +} + +/****************************************************** + editUndoGetCommand +******************************************************/ +int editUndoGetCommand() +{ + return undoData.command; +} + +/****************************************************** + editClipboardGet +******************************************************/ +void editClipboardGet(GCLINK **plink,int *plinkType) +{ + if (clipData.linkType == GROUP){ + *plink = (GCLINK *)alCopyGroup((GLINK *)clipData.link); + } else { + *plink = (GCLINK *)alCopyChan((CLINK *)clipData.link); + } + *plinkType = clipData.linkType; +} + +/****************************************************** + editClipboardSet +******************************************************/ +void editClipboardSet(GCLINK *link,int linkType) +{ + if (clipData.linkType == GROUP) + alDeleteGroup((GLINK *)clipData.link); + else + alDeleteChan((CLINK *)clipData.link); + + if (linkType == GROUP){ + clipData.link = (GCLINK *)alCopyGroup((GLINK *)link); + } else { + clipData.link = (GCLINK *)alCopyChan((CLINK *)link); + } + clipData.linkType = linkType; +} + +/****************************************************** + editCutLink +******************************************************/ +void editCutLink(ALINK *area,GCLINK *link,int linkType) +{ + struct subWindow *groupWindow,*treeWindow; + GLINK *parent; + GCLINK *linkTemp; + int diffCount, count=0; + struct anyLine *treeLine; + struct anyLine *groupLine; + struct anyLine *line; + WLINE *wline=0; + Widget pushButton = 0; + XmPushButtonCallbackStruct *cbs=NULL; + + if (!link) return; + + treeWindow = area->treeWindow; + groupWindow = area->groupWindow; + + diffCount = link->viewCount; + treeLine = (struct anyLine *)link->lineTreeW; + groupLine = (struct anyLine *)link->lineGroupW; + + /* treeWindow selection */ + if (link == treeWindow->selectionLink){ + + /* adjust lines of treeWindow*/ + /* + line= treeLine; + count = diffCount; + while (count){ + line->link = 0; + line = (struct anyLine *)sllNext(line); + if (!line) break; + count--; + } + */ + + /* adjust lines in groupWindow */ + /* + line = (struct anyLine *)sllFirst(groupWindow->lines); + while (line){ + line->link = 0; + line = (struct anyLine *)sllNext(line); + } + */ + + /* adjust treeWindow viewCount */ + linkTemp=link; + while (TRUE){ + linkTemp = (GCLINK *)linkTemp->parent; + if (linkTemp == NULL ) break; + linkTemp->viewCount -= diffCount; + count = linkTemp->viewCount; + } + setViewConfigCount(area->treeWindow,count); + + /* update line data */ + /* + link->lineTreeW = NULL; + link->lineGroupW = NULL; + */ + + /* remove selected group from parent's childlist*/ + alRemoveGroup((GLINK *)link); + + /* adjust treeSym for treeWindow */ + parent = (GLINK *)link->parent; + alViewAdjustTreeW(parent, NOCHANGE, area->viewFilter); + + /* redraw tree window */ + line = (struct anyLine *)parent->lineTreeW; + if (line) { + redraw(treeWindow, line->lineNo); + wline = (WLINE *)line->wline; + if (wline) pushButton = wline->name; + } + else redraw(treeWindow,0); + + /* adjust groupWindow */ + groupWindow = area->groupWindow; + groupWindow->parentLink = parent; + groupWindow->viewConfigCount = alViewAdjustGroupW((GLINK *)parent, + area->viewFilter); + + /* redraw Group window */ + if (pushButton) nameTreeW_callback(pushButton, line, cbs); + + } + + /* groupWindow selection */ + else if (link == groupWindow->selectionLink){ + + + /* adjust groupWindow selection */ + markSelectedWidget(groupWindow,0); + markSelection(groupWindow, 0); + + /* make treeWindow selection the active selection */ + area->selectionWindow = treeWindow; + area->selectionWidget = treeWindow->selectionWidget; + area->selectionLink = treeWindow->selectionLink; + area->selectionType = GROUP; + + /* update dialog windows */ + axUpdateDialogs(area); + + /* adjust treeWindow */ + if (treeLine) { + + /* adjust lines of treeWindow*/ + line = treeLine; + count = diffCount; + while (count){ + line->link = 0; + line = (struct anyLine *)sllNext(line); + if (!line) break; + count--; + } + + /* adjust viewCount of treeWindow*/ + linkTemp = link; + while (TRUE){ + linkTemp = (GCLINK *)linkTemp->parent; + if (linkTemp == NULL ) break; + linkTemp->viewCount -= diffCount; + count = linkTemp->viewCount; + } + setViewConfigCount(area->treeWindow,count); + } + + /* adjust line of groupWindow */ + groupLine->link = 0; + + /* adjust viewCount of groupWindow*/ + groupWindow->viewConfigCount -= 1; + + /* delete selected group or channel */ + if (groupLine->linkType == GROUP){ + alRemoveGroup((GLINK *)link); + } else { + alRemoveChan((CLINK *)link); + } + + /* adjust treeSym for treeWindow */ + parent = (GLINK *)link->parent; + alViewAdjustTreeW(parent, NOCHANGE, area->viewFilter); + + /* redraw windows */ + if (treeLine){ + line = (struct anyLine *)parent->lineTreeW; + if (line) redraw(treeWindow, line->lineNo); + else redraw(treeWindow,0); + } + + redraw(groupWindow,groupLine->lineNo); + + } + + /* not a selection */ + else { + + /* delete selected group or channel */ + if (groupLine->linkType == GROUP){ + alRemoveGroup((GLINK *)link); + } else { + alRemoveChan((CLINK *)link); + } + + /* adjust treeWindow */ + if (treeLine) { + + /* adjust lines of treeWindow*/ + line = treeLine; + count = diffCount; + while (count){ + line->link = 0; + line = (struct anyLine *)sllNext(line); + if (!line) break; + count--; + } + + /* adjust viewCount of treeWindow*/ + linkTemp = link; + while (TRUE){ + linkTemp = (GCLINK *)linkTemp->parent; + if (linkTemp == NULL ) break; + linkTemp->viewCount -= diffCount; + count = linkTemp->viewCount; + } + setViewConfigCount(area->treeWindow,count); + + /* adjust treeSym for treeWindow */ + parent = (GLINK *)link->parent; + alViewAdjustTreeW(parent, NOCHANGE, area->viewFilter); + + /* redraw windows */ + line = (struct anyLine *)parent->lineTreeW; + if (line) redraw(treeWindow, line->lineNo); + else redraw(treeWindow,0); + + } + + if (groupLine) { + /* adjust line of groupWindow */ + groupLine->link = 0; + + /* adjust viewCount of groupWindow*/ + groupWindow->viewConfigCount -= 1; + + redraw(groupWindow,groupLine->lineNo); + + } + + } + + /* update arrow */ + if (link->parent->lineTreeW) + awRowWidgets(link->parent->lineTreeW,area); + if (link->parent->lineGroupW) + awRowWidgets(link->parent->lineGroupW,area); + +} + +/****************************************************** + editInsertFile +******************************************************/ +void editInsertFile(char *filename,ALINK *area) +{ + GCLINK *newLink; + GLINK *linkHold; + + linkHold = (GLINK *)sllFirst(area->pmainGroup); + alGetConfig(area->pmainGroup,filename,CA_CONNECT_NO); + if (!sllFirst(area->pmainGroup)){ + createDialog(area->form_main,XmDIALOG_ERROR,filename, + " is not a valid alarm configuration file."); + return; + } + newLink = (GCLINK *)sllFirst(area->pmainGroup); + ((GCLINK *)newLink)->viewCount = 1; + area->pmainGroup->p1stgroup = linkHold; + + editPasteLink(area, newLink, GROUP); + +} + +/****************************************************** + editPasteLink +******************************************************/ +void editPasteLink(ALINK *area,GCLINK *newLink,int linkType) +{ + struct subWindow *treeWindow; + GCLINK *parentLink; + GCLINK *selectLink; + int selectType; + + if (!newLink) return; + + selectLink = (GCLINK *)area->selectionLink; + selectType = area->selectionType; + + treeWindow = area->treeWindow; + + editUndoSet( NULL, linkType, (GCLINK *)newLink, + MENU_EDIT_UNDO_CUT_NOSELECT, ALH_DELETE); + + if (linkType == GROUP){ + + /* add/insert group link */ + parentLink = treeWindow->selectionLink; + if ( selectLink == parentLink || selectLink == NULL || + selectType == CHANNEL ){ + alPrecedeGroup((GLINK *)parentLink, NULL, (GLINK *)newLink); + } else { + alPrecedeGroup((GLINK *)parentLink,(GLINK *)selectLink, + (GLINK *)newLink); + } + + awViewNewGroup(area, (GCLINK *)newLink); + + } else { + + /* add/insert channel link */ + parentLink = treeWindow->selectionLink; + if ( selectLink == parentLink || selectLink == NULL || + selectType == GROUP){ + alPrecedeChan((GLINK *)parentLink, NULL, (CLINK *)newLink); + } else { + alPrecedeChan((GLINK *)parentLink,(CLINK *)selectLink, + (CLINK *)newLink); + } + + awViewNewChan(area, (GCLINK *)newLink); + + } + + /* update arrow */ + if (newLink->parent->lineTreeW) + awRowWidgets(newLink->parent->lineTreeW,area); + if (newLink->parent->lineGroupW) + awRowWidgets(newLink->parent->lineGroupW,area); + +} + diff --git a/awView.c b/awView.c new file mode 100644 index 0000000..6300e2d --- /dev/null +++ b/awView.c @@ -0,0 +1,785 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* awView.c */ + +/************************DESCRIPTION*********************************** + This file contains routines for altering the users view +**********************************************************************/ + +#define DEBUG_CALLBACKS 0 + +#include + +#include "alh.h" +#include "alLib.h" +#include "sllLib.h" +#include "axArea.h" +#include "axSubW.h" +#include "line.h" +#include "ax.h" + +/* structures for arrow button single vs double click action */ +struct timeoutData { + Widget pushButton; + void *gdata; + XtIntervalId timeoutId; +}; + +static void singleClickTreeW_callback(XtPointer cd, XtIntervalId *id); +static void singleClickNameGroupW_callback(XtPointer cd, XtIntervalId *id); +static void singleClickArrowGroupW_callback(XtPointer cd, XtIntervalId *id); + +/*************************************************** + doubleClickNameGroupW_callback +****************************************************/ +static void doubleClickNameGroupW_callback(Widget pushButton,struct anyLine *line, +XmPushButtonCallbackStruct *cbs) +{ + struct subWindow *treeWindow; + struct subWindow *groupWindow; + GLINK *parent; + GCLINK *link; + WLINE *wline; + ALINK *area; + int grandparentsOpen; + GLINK *glinkTemp; + + struct anyLine *l; + + XtVaGetValues(pushButton, XmNuserData, &l, NULL); + groupWindow = l->pwindow; + + area = groupWindow->area; + + if (line->linkType == GROUP ) { + + link = line->link; + parent = link->parent; + + treeWindow = area->treeWindow; + + /* update tree window */ + grandparentsOpen = TRUE; + glinkTemp=parent->parent; + while (glinkTemp){ + if ( glinkTemp->viewCount <= 1 ) grandparentsOpen = FALSE; + glinkTemp = glinkTemp->parent; + } + if ( grandparentsOpen ){ + if ( parent->viewCount <= 1 ){ + displayNewViewTree(area,parent,EXPANDCOLLAPSE1); + } + } + + /*groupWindow must now display contents of new treeWindow selection */ + markSelectedWidget(groupWindow,NULL); + markSelection(groupWindow, NULL); + groupWindow->parentLink = link; + groupWindow->viewConfigCount = alViewAdjustGroupW((GLINK *)link, + area->viewFilter); + groupWindow->viewOffset = 0; + redraw(groupWindow,0); + + /* markSelection */ + area->selectionLink = link; + area->selectionType = GROUP; + area->selectionWindow = treeWindow; + treeWindow->selectionLink = link; + + /* update dialog windows */ + axUpdateDialogs(area); + + /* markSelectedWidget */ + if (link->lineTreeW) { + wline = ((struct anyLine *)link->lineTreeW)->wline; + markSelectedWidget(treeWindow,wline->name); + } else { + markSelectedWidget(treeWindow,NULL); + } + } else { + markSelectedWidget(groupWindow,pushButton); + markSelection(groupWindow, line); + + /* update dialog windows if displayed */ + axUpdateDialogs(area); + } +} + +/*************************************************** + nameTreeW_callback +****************************************************/ +void nameTreeW_callback(Widget pushButton,struct anyLine *line, +XmPushButtonCallbackStruct *cbs) +{ + struct subWindow *subWindow; + struct subWindow *groupWindow; + + struct anyLine *l; + + if (pushButton) { + XtVaGetValues(pushButton, XmNuserData, &l, NULL); + subWindow = l->pwindow; + } + else { + return; + } + + /* groupWindow must now display contents of new treeWindow selection */ + groupWindow = ((ALINK *)subWindow->area)->groupWindow; + markSelectedWidget(groupWindow,NULL); + markSelection(groupWindow, NULL); + if (line) { + groupWindow->parentLink = line->link; + groupWindow->viewConfigCount = alViewAdjustGroupW((GLINK *)line->link, + ((ALINK *)subWindow->area)->viewFilter); + } + groupWindow->viewOffset = 0; + redraw(groupWindow,0); + + markSelectedWidget(subWindow,pushButton); + markSelection(subWindow, line); + + /* update dialog windows */ + axUpdateDialogs(subWindow->area); +} + +/****************************************************** + singleClickTreeW_callback +******************************************************/ +static void singleClickTreeW_callback(XtPointer cd, XtIntervalId *id) +{ + ALINK *area; + struct timeoutData *pdata = (struct timeoutData *)cd; + +#if DEBUG_CALLBACKS + { + static int n=0; + + printf("singleClickTreeW_callback: n=%d\n",n++); + } +#endif + + XtVaGetValues(pdata->pushButton, XmNuserData, &area, NULL); + + pdata->timeoutId= 0; + displayNewViewTree(area,(GLINK *)pdata->gdata,EXPANDCOLLAPSE1); +} + +/*************************************************** + arrowTreeW_callback +****************************************************/ +void arrowTreeW_callback(Widget pushButton,void *glink, +XmPushButtonCallbackStruct *cbs) +{ + void *area; + static unsigned long interval=0; + static struct timeoutData data; + + if (cbs->click_count == 1){ + /* Get multi-click time in ms */ + if (!interval) interval = XtGetMultiClickTime(display); + data.pushButton = pushButton; + data.gdata = (void *)glink; + if ( data.timeoutId== 0 ) { + data.timeoutId= XtAppAddTimeOut(appContext,interval, + singleClickTreeW_callback,(XtPointer)&data); + } + + } else if (cbs->click_count == 2) { + if (data.timeoutId) { + XtRemoveTimeOut(data.timeoutId); + data.timeoutId=0; + } + XtVaGetValues(pushButton, XmNuserData, &area, NULL); + displayNewViewTree(area,glink,EXPAND); + } +} + +/*************************************************** + nameGroupW_callback +****************************************************/ +void nameGroupW_callback(Widget pushButton,struct anyLine *line, +XmPushButtonCallbackStruct *cbs) +{ + void *area; + static unsigned long interval=0; + static struct timeoutData data; + struct subWindow *groupWindow; + + struct anyLine *l; + + XtVaGetValues(pushButton, XmNuserData, &l, NULL); + groupWindow = l->pwindow; + + area = groupWindow->area; + + if (line->linkType == GROUP ) { + if (cbs->click_count == 1){ + /* Get multi-click time in ms */ + if (!interval) interval = XtGetMultiClickTime(display); + data.pushButton = pushButton; + data.gdata = (void *)line; + if (data.timeoutId == 0) { + data.timeoutId= XtAppAddTimeOut(appContext,interval, + singleClickNameGroupW_callback,(XtPointer)&data); + } + } else if (cbs->click_count == 2) { + if (data.timeoutId) { + XtRemoveTimeOut(data.timeoutId); + data.timeoutId=0; + } + doubleClickNameGroupW_callback(pushButton, line, cbs); + } + } else { + markSelectedWidget(groupWindow,pushButton); + markSelection(groupWindow, line); + + /* update dialog windows if displayed */ + axUpdateDialogs(area); + } +} + +/****************************************************** + singleClickNameGroupW_callback +******************************************************/ +static void singleClickNameGroupW_callback(XtPointer cd, XtIntervalId *id) +{ + void *area; + struct subWindow *groupWindow; + struct timeoutData *pdata = (struct timeoutData *)cd; + + struct anyLine *l; + +#if DEBUG_CALLBACKS + { + static int n=0; + + printf("singleClickNameGroupW_callback: n=%d\n",n++); + } +#endif + + pdata->timeoutId= 0; + + XtVaGetValues(pdata->pushButton, XmNuserData, &l, NULL); + groupWindow = l->pwindow; + + area = groupWindow->area; + + markSelectedWidget(groupWindow,pdata->pushButton); + markSelection(groupWindow,pdata->gdata); + + /* update dialog windows if displayed */ + axUpdateDialogs(area); + +} + +/****************************************************** + singleClickArrowGroupW_callback +******************************************************/ +static void singleClickArrowGroupW_callback(XtPointer cd, XtIntervalId *id) +{ + ALINK *area; + GCLINK *link; + GLINK *parent; + GLINK *glinkTemp; + struct subWindow *treeWindow; + int grandparentsOpen; + struct timeoutData *pdata = (struct timeoutData *)cd; + +#if DEBUG_CALLBACKS + { + static int n=0; + + printf("singleClickArrowTreeW_callback: n=%d\n",n++); + } +#endif + + pdata->timeoutId= 0; + + XtVaGetValues(pdata->pushButton, XmNuserData, &area, NULL); + + link = pdata->gdata; + parent = link->parent; + + treeWindow = area->treeWindow; + + /* update tree window */ + grandparentsOpen = TRUE; + glinkTemp=parent->parent; + while (glinkTemp){ + if ( glinkTemp->viewCount <= 1 ) grandparentsOpen = FALSE; + glinkTemp = glinkTemp->parent; + } + if ( grandparentsOpen ){ + if ( parent->viewCount <= 1 ){ + displayNewViewTree(area,parent,EXPANDCOLLAPSE1); + } + displayNewViewTree(area,(GLINK *)link,EXPANDCOLLAPSE1); + } +} + +/*************************************************** + arrowGroupW_callback +****************************************************/ +void arrowGroupW_callback(Widget pushButton,void *glink, +XmPushButtonCallbackStruct *cbs) +{ + void *area; + static unsigned long interval=0; + static struct timeoutData data; + + if (cbs->click_count == 1){ + /* Get multi-click time in ms */ + if (!interval) interval = XtGetMultiClickTime(display); + data.pushButton = pushButton; + data.gdata = (void *)glink; + if ( data.timeoutId== 0 ) { + data.timeoutId= XtAppAddTimeOut(appContext,interval, + singleClickArrowGroupW_callback,(XtPointer)&data); + } + } else if (cbs->click_count == 2) { + if (data.timeoutId) { + XtRemoveTimeOut(data.timeoutId); + data.timeoutId=0; + } + XtVaGetValues(pushButton, XmNuserData, &area, NULL); + singleClickArrowGroupW_callback((XtPointer)&data,NULL); + displayNewViewTree(area,glink,EXPAND); + } +} + +/*************************************************** + markSelection +****************************************************/ +void markSelection(struct subWindow *subWindow,struct anyLine *line) +{ + if (!line) subWindow->selectionLink = 0; + else subWindow->selectionLink = line->link; + + markSelectionArea(subWindow->area,line); + return; +} + +/*************************************************** + createConfigDisplay +****************************************************/ +void createConfigDisplay(ALINK *area,int expansion) +{ + GLINK *glinkTop; + int viewConfigCount; + + /* are the following 2 lines necessary??? */ + initializeSubWindow(area->treeWindow); + initializeSubWindow(area->groupWindow); + + if ( !area->pmainGroup ) return; + + glinkTop = (GLINK *)sllFirst(area->pmainGroup); + glinkTop->viewCount = 0; + + viewConfigCount = alViewAdjustTreeW(glinkTop, expansion, area->viewFilter); + setViewConfigCount(area->treeWindow,viewConfigCount); + setParentLink(area->treeWindow,glinkTop); + + viewConfigCount = alViewAdjustGroupW((void *)glinkTop,area->viewFilter); + setViewConfigCount(area->groupWindow,viewConfigCount); + setParentLink(area->groupWindow,glinkTop); + + /* Create Tree Display: starting at top level */ + if (area->mapped){ + redraw(area->treeWindow,0); + + /* mark first line as treeWindow selection */ + /* and redraw groupWindow */ + defaultTreeSelection(area); + } +} + +/*************************************************** + displayNewViewTree +****************************************************/ +void displayNewViewTree(ALINK *area,GLINK *glink,int command) +{ + struct anyLine *line; + int viewConfigCount; + + if (!glink) return; + + viewConfigCount = alViewAdjustTreeW(glink, command,area->viewFilter); + setViewConfigCount(area->treeWindow,viewConfigCount); + line = (struct anyLine *)glink->lineTreeW; + if (line) redraw(area->treeWindow, line->lineNo); + else redraw(area->treeWindow,0 ); +} + +/*************************************************** + redraw +****************************************************/ +void redraw(struct subWindow *subWindow,int rowNumber) +{ + struct anyLine *line=0; + struct anyLine *ptline; + int row, r, linkType; + GCLINK *link; + GCLINK *ptlink; + GCLINK *linkOld; + WLINE *wline; + WLINE *ptwline; + SNODE *pt; + + row = rowNumber; + + /* adjust view offset if more groups will fit on display */ + if (subWindow->viewOffset && subWindow->viewRowCount && + (int)subWindow->viewOffset + subWindow->viewRowCount > + subWindow->viewConfigCount ){ + + subWindow->viewOffset = Mmax(subWindow->viewConfigCount - + subWindow->viewRowCount,0); + row = 0; + } + + r = 0; + if (subWindow->lines) { + line = (struct anyLine *)sllFirst(subWindow->lines); + while (line){ + if (line->lineNo >= row) break; + line = (struct anyLine *)sllNext(line); + r++; + } + } + row = r; + + + link = (GCLINK *)(subWindow->alViewNth)(subWindow->parentLink,&linkType,0); + initSevrAbove(subWindow,link); + + link = (GCLINK *)(subWindow->alViewNth)(subWindow->parentLink, + &linkType,subWindow->viewOffset+row); + + + while ( link ){ + + if (!line){ + line = (struct anyLine *)awAllocLine(); + sllAdd(subWindow->lines,(SNODE *)line); + wline = (WLINE *)XtCalloc(1 , sizeof(WLINE)); + line->wline = (void *)wline; + } else { + linkOld = (GCLINK *)line->link; + if (linkOld){ + line->linkType = 0; + line->link = NULL; + line->cosCallback = NULL; + linkOld->modified = 0; + if(isTreeWindow(subWindow->area,subWindow)){ + if ( (struct anyLine *)linkOld->lineTreeW && + ((struct anyLine *)linkOld->lineTreeW)->lineNo >= row) + linkOld->lineTreeW = NULL; + } else { + if ( (struct anyLine *)linkOld->lineGroupW && + ((struct anyLine *)linkOld->lineGroupW)->lineNo >= row) + linkOld->lineGroupW = NULL; + } + } + } + line->pwindow= (void *)subWindow; + line->lineNo = row; + line->linkType = linkType; + wline = (WLINE *)line->wline; + if (wline->name && subWindow->selectionWidget && + wline->name == subWindow->selectionWidget) + markSelectedWidget(subWindow,NULL); + line->link = (void *)link; + line->pname = ((GCLINK *)link)->pgcData->name; + if (((GCLINK *)link)->pgcData->alias){ + line->alias = ((GCLINK *)link)->pgcData->alias; + } else { + line->alias = ((GCLINK *)link)->pgcData->name; + } + if(isTreeWindow(subWindow->area,subWindow)) + link->lineTreeW = (void *)line; + else link->lineGroupW = (void *)line; + if (linkType == GROUP){ + awUpdateGroupLine(line); + } else if (linkType == CHANNEL){ + awUpdateChanLine(line); + } + + /* call subwindow create/change row widgets routine */ + awRowWidgets(line,subWindow->area); + + if (line->link == subWindow->selectionLink){ + markSelectedWidget(subWindow,wline->name); + } + + + /* determine viewRowCount if not already set */ + if ( !subWindow->rowHeight){ + + XtVaGetValues(subWindow->drawing_area, + XmNheight, &subWindow->viewHeight, + XmNmarginHeight, &subWindow->marginHeight, + NULL); + + XtVaGetValues(wline->row_widget, + XmNheight, &subWindow->rowHeight, + NULL); + + /* ****** NOTE: ALL ROWS MUST BE THE SAME HEIGHT*********** */ + subWindow->viewRowCount = calcRowCount(subWindow); + + } + + if (line ) line = (struct anyLine *)sllNext(line); + row++; + if (row >= subWindow->viewRowCount) break; + if (row >= subWindow->viewConfigCount) break; + + link = (GCLINK *)(subWindow->alViewNext)(link,&linkType); + } + + /* adjustManagedRows */ + pt = (SNODE *)line; + while (pt){ + ptline = (struct anyLine *)pt; + ptwline = (WLINE *)ptline->wline; + if (XtIsManaged(ptwline->row_widget) == TRUE ){ + XtUnmanageChild(ptwline->row_widget); + } + ptlink = (GCLINK *)ptline->link; + if (ptlink) { + ptlink->modified = 0; + if (isTreeWindow(subWindow->area, subWindow) ) { + ptlink->lineTreeW = NULL; + } else { + ptlink->lineGroupW = NULL; + } + } + initLine(ptline); + pt = sllNext(pt); + } + + adjustScrollBar(subWindow); + + if (link) { + link = (GCLINK *)(subWindow->alViewNext)(link,&linkType); + initSevrBelow(subWindow,link); + } +} + +/*************************************************** + invokeLinkUpdate +****************************************************/ +void invokeLinkUpdate(GCLINK *link,int linkType) +{ + void *line; + + if (link && link->modified ){ + line = link->lineGroupW; + if (line) { + if (linkType == GROUP) awUpdateGroupLine(line); + else if (linkType == CHANNEL) awUpdateChanLine(line); + awUpdateRowWidgets(line); + } + line = link->lineTreeW; + if (line) { + if (linkType == GROUP) awUpdateGroupLine(line); + else if (linkType == CHANNEL) awUpdateChanLine(line); + awUpdateRowWidgets(line); + } + link->modified = 0; + } +} + +/*************************************************** + awViewAddNewAlarm +****************************************************/ +void awViewAddNewAlarm (CLINK *clink,int prevCount,int count) +{ + ALINK *area; + int prevViewCount; + int newLineTree; + GLINK *glink; + GLINK *viewParent; + GLINK *prevLink; + GLINK *addViewLink=NULL; + struct subWindow *subWindowTree; + struct subWindow *subWindowGroup; + + area = clink->pmainGroup->area; + + if (!area || prevCount || !count) return; + + newLineTree = FALSE; + viewParent = NULL; + prevViewCount = 1; + prevLink = 0; + + glink = clink->parent; + if (!glink) return; + while (glink) { + /* view parent open */ + if (glink->viewCount >1 && !prevViewCount) { + viewParent = glink; + addViewLink = prevLink; + if (prevLink) newLineTree = TRUE; + } + /* view parent NOT open */ + if (glink->viewCount == 1) { + viewParent = glink; + addViewLink = prevLink; + newLineTree = FALSE; + } + prevLink = glink; + prevViewCount = glink->viewCount; + if (newLineTree) glink->viewCount++; + glink = glink->parent; + + } + + subWindowTree = (struct subWindow *)area->treeWindow; + subWindowGroup = (struct subWindow *)area->groupWindow; + + if (!viewParent || !prevViewCount) { + addViewLink = prevLink; + viewParent = prevLink; + newLineTree = TRUE; + } + + if (newLineTree) { + subWindowTree->modified = 1; + clink->pmainGroup->modified = 1; + subWindowTree->viewConfigCount++; + if (addViewLink) addViewLink->viewCount=1; + if (viewParent){ + if (newLineTree) + alViewAdjustTreeW(viewParent,NOCHANGE,area->viewFilter); + } + } + if (!(GLINK *)subWindowGroup->parentLink || + (viewParent == (GLINK *)subWindowGroup->parentLink)) { + subWindowGroup->modified =1; + clink->pmainGroup->modified = 1; + subWindowGroup->viewConfigCount++; + if (addViewLink) addViewLink->viewCount=1; + } +} + +/****************************************************** + awViewNewGroup +******************************************************/ +void awViewNewGroup(ALINK *area,GCLINK *link) +{ + struct subWindow *groupWindow,*treeWindow; + GLINK *parent, *glink; + GCLINK *gclink; + int diffCount, line; + + treeWindow = area->treeWindow; + groupWindow = area->groupWindow; + parent = (GLINK *)link->parent; + + diffCount = link->viewCount; + /* update changed treeWindow */ + if (parent && parent->viewCount > 1) { + + /* adjust viewCounts of open parents */ + glink=parent; + while (glink){ + glink->viewCount += diffCount; + glink = (GLINK *)glink->parent; + } + + /* adjust treeWindow viewCount */ + treeWindow->viewConfigCount += diffCount; + + /* update treeSym for treeWindow */ + alViewAdjustTreeW(parent, NOCHANGE, area->viewFilter); + + /* redraw treeWindow */ + line = 0; + if (parent->lineTreeW) { + line = ((struct anyLine *)parent->lineTreeW)->lineNo; + } + redraw(treeWindow,line); + + } + + /* update groupWindow configCount*/ + if (parent == groupWindow->parentLink){ + groupWindow->viewConfigCount++; + + gclink = groupWindow->selectionLink; + if (gclink) { + line = ((struct anyLine *)gclink->lineGroupW)->lineNo; + if ( link && (line == groupWindow->viewRowCount) ){ + groupWindow->viewOffset++; + } + } + redraw(groupWindow,0); + } +} + +/****************************************************** + awViewNewChan +******************************************************/ +void awViewNewChan(ALINK *area,GCLINK *link) +{ + struct subWindow *groupWindow; + int line; + GCLINK *gclink; + + groupWindow = area->groupWindow; + + /* adjust groupWindow configCount*/ + groupWindow->viewConfigCount++; + + /* redraw groupWindow */ + gclink = groupWindow->selectionLink; + if (gclink){ + line = ((struct anyLine *)gclink->lineGroupW)->lineNo; + if ( link && (line == groupWindow->viewRowCount) ){ + groupWindow->viewOffset++; + } + } + redraw(groupWindow,0); +} + +/****************************************************** + awViewViewCount +******************************************************/ +int awViewViewCount(GCLINK *gclink) +{ + int viewCount = 0; + + if (gclink->pmainGroup->area) + viewCount = (((ALINK *)gclink->pmainGroup->area)->viewFilter)(gclink); + + return(viewCount); +} + +/****************************************************** + invokeDialogUpdate +******************************************************/ + +void invokeDialogUpdate(ALINK *area) +{ + GCLINK *gclink; + + gclink = area->selectionLink; + if (gclink && gclink->modified) axUpdateDialogs(area); +} + diff --git a/ax.h b/ax.h new file mode 100644 index 0000000..e56e85a --- /dev/null +++ b/ax.h @@ -0,0 +1,456 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* ax.h */ + +/************************DESCRIPTION*********************************** + alh function prototypes +**********************************************************************/ + +#ifndef INCaxh +#define INCaxh + +#include +#include + +#include "alh.h" +#include "axSubW.h" +#include "line.h" +#include "alLib.h" +#include "axArea.h" + +/******************************************************************** + alarm.c function prototypes +*********************************************************************/ + +void alhAlarmStringInit(); + + +/******************************************************************** + axArea.c function prototypes +*********************************************************************/ + +Widget buildPulldownMenu( Widget parent, char *menu_title, char menu_mnemonic, +int tearOff, MenuItem *items, XtPointer user_data); +void setupConfig( char *filename, int program, ALINK *areaOld); +void markActiveWidget( ALINK *area, Widget newWidget); +void createMainWindowWidgets( ALINK *area); +int isTreeWindow( ALINK *area, void * subWindow); +void markSelectionArea( ALINK *area, struct anyLine *line); +void changeBeepSeverityText( ALINK *area); +void changeSilenceForeverText( ALINK *area); +void updateDisabledForcePVCount(ALINK *area, int count); +void unmapArea_callback( Widget main, Widget w, XmAnyCallbackStruct *cbs); +void axMakePixmap( Widget w); +void axUpdateDialogs(ALINK *area); +void *getSelectionLinkArea(ALINK *area); +int getSelectionLinkTypeArea(ALINK *area); +Widget createActionButtons(Widget parent,ActionAreaItem *actions,int num_buttons); +void showMainWindow(ALINK *area); + + +/******************************************************************** + axRunW.c function prototypes +*********************************************************************/ + +void pixelData(Widget iconBoard); +XtErrorMsgHandler trapExtraneousWarningsHandler( String message); +void createRuntimeWindow( ALINK *area); +void silenceCurrentReset(void *area); +void silenceCurrent_callback( Widget w, ALINK* area, XmAnyCallbackStruct *call_data); +void silenceForeverChangeState( ALINK *area); +void silenceOneHour_callback( Widget w, ALINK* area, XmAnyCallbackStruct *call_data); + + +/******************************************************************** + axSubW.c function prototypes +*********************************************************************/ + +void setParentLink( struct subWindow *subWindow, void *link); +void setLineRoutine( void *area, struct subWindow *subWindow,int program); +void markSelectedWidget( struct subWindow *subWindow, Widget newWidget); +void initializeSubWindow( struct subWindow *subWindow); +void setViewConfigCount( struct subWindow *subWindow, int count); +void invokeSubWindowUpdate( struct subWindow *subWindow); +struct subWindow *createSubWindow( void *area); +void createSubWindowWidgets( struct subWindow *subWindow, Widget parent); +int calcRowCount( struct subWindow *subWindow); +int calcRowYValue( struct subWindow *subWindow, int lineNo); +void adjustScrollBar( struct subWindow *subWindow); +void exposeResizeCallback( Widget widget, struct subWindow *subWindow, +XEvent *cbs); +void defaultTreeSelection( ALINK * area); +void initSevrAbove( struct subWindow *subWindow, void *link); +void initSevrBelow( struct subWindow *subWindow, void *link); + +/******************************************************************** + browser.c function prototypes +*********************************************************************/ + +int callBrowser(char *url); + +/******************************************************************** + dialog.c function prototypes +*********************************************************************/ + +Widget createFileDialog( Widget parent, void *okCallback, XtPointer okParm, +void *cancelCallback, XtPointer cancelParm, XtPointer userParm,String title, +String pattern, String dirSpec); +void createDialog( Widget parent, int dialogType, char *message1, char *message2); +void createActionDialog( Widget parent, int dialogType, String message1, +XtCallbackProc okCallback, XtPointer okParm, XtPointer userParm); +void errMsg(const char *fmt, ...); +void fatalErrMsg(const char *fmt, ...); + +/******************************************************************** + file.c function prototypes +*********************************************************************/ + +void exit_quit(Widget w, XtPointer clientdata, XtPointer calldata); +void fileSetupCallback( Widget widget, int client_data, XmFileSelectionBoxCallbackStruct *cbs); +void fileCancelCallback( Widget widget, ALINK *area, XmFileSelectionBoxCallbackStruct *cbs); +void fileSetupInit(Widget widget,int argc,char *argv[]); +char *shortfile(char *name); + +/******************************************************************** + acknowledge.c function prototypes +*********************************************************************/ + +void ack_callback( Widget widget, struct anyLine *line, XmAnyCallbackStruct *cbs); +void ackChan(CLINK *clink); + +/******************************************************************** + awView.c function prototypes +*********************************************************************/ + +void nameTreeW_callback( Widget pushButton, struct anyLine *line, +XmPushButtonCallbackStruct *cbs); +void nameGroupW_callback( Widget pushButton, struct anyLine *line, +XmPushButtonCallbackStruct *cbs); +void arrowTreeW_callback( Widget pushButton, void *glink, +XmPushButtonCallbackStruct *cbs); +void arrowGroupW_callback( Widget pushButton, void *glink, +XmPushButtonCallbackStruct *cbs); +void createConfigDisplay( ALINK *area, int expansion); +void displayNewViewTree( ALINK *area, GLINK *glink, int command); +void redraw( struct subWindow *subWindow, int rowNumber); +void invokeLinkUpdate( GCLINK *link, int linkType); +void markSelection( struct subWindow *subWindow, struct anyLine *line); +void awViewAddNewAlarm(CLINK *clink,int prevViewCount,int viewCount); +void awViewNewGroup( ALINK *area, GCLINK *link); +void awViewNewChan( ALINK *area, GCLINK *link); +int awViewViewCount( GCLINK *link); +void invokeDialogUpdate( ALINK *area); + + +/******************************************************************** + guidance.c function prototypes +*********************************************************************/ + +void guidanceCallback( Widget widget, GCLINK *link, XmAnyCallbackStruct *cbs); +int guidanceExists(GCLINK *link); +int guidanceDisplay(GCLINK *link); +void guidanceCopyGuideList(SLIST *pToGuideList,SLIST *pFromGuideList); +void guidanceDeleteGuideList(SLIST *pGuideList); + + +/******************************************************************** + process.c function prototypes +*********************************************************************/ + +void processSpawn_callback( Widget w, char *command, void *call_data); +void relatedProcess_callback( void *widget, GCLINK *link, void *cbs); + + +/******************************************************************** + alFilter.c function prototypes +*********************************************************************/ + +int alFilterAll( GCLINK *gclink); +int alFilterAlarmsOnly( GCLINK *gclink); +int alFilterUnackAlarmsOnly( GCLINK *gclink); + + +/******************************************************************** + alLib.c function prototypes +*********************************************************************/ + +struct mainGroup *alAllocMainGroup(void); +void alAddGroup( GLINK *parent, GLINK *glink); +void alAddChan( GLINK *parent, CLINK *clink); +void alPrecedeGroup( GLINK *parent, GLINK *sibling, GLINK *glink); +void alPrecedeChan( GLINK *parent, CLINK *sibling, CLINK*clink); +void alDeleteChan( CLINK *clink); +void alDeleteGroup( GLINK *glink); +void alRemoveGroup( GLINK *glink); +void alRemoveChan( CLINK *clink); +void alSetPmainGroup( GLINK *glink, struct mainGroup *pmainGroup); +GLINK *alCopyGroup(GLINK *glink); +CLINK *alCopyChan(CLINK *clink); +GLINK *alCreateGroup(); +CLINK *alCreateChannel(); +void alSetMask( char *s4, MASK *mask); +void alGetMaskString( MASK mask, char *s); +void alNewAlarm( int stat, int sev, char *value, CLINK *clink); +void alSaveAlarmEvent(int stat,int sevr,int acks,int ackt,char *value,CLINK *clink); +void alConnectEvent(CLINK *clink); +void alNewEvent(int stat,int sevr,int acks,int ackt,char *value,CLINK *clink); +void alHighestSystemSeverity(GLINK * glink); +short alHighestSeverity( int sevr[ALH_ALARM_NSEV]); +void alForceChanMask( CLINK *clink, int index, int op); +void alForceGroupMask( GLINK *glink, int index, int op); +void alChangeChanMask( CLINK *clink, MASK mask); +void alChangeGroupMask( GLINK *glink, MASK mask); +void alResetGroupMask( GLINK *glink); +char *alAlarmGroupName( GLINK *link); +int alProcessExists( GCLINK *link); +void alSetUnackSevChan(CLINK *clink,int newSevr); +void alSetCurChanMask(CLINK *clink,MASK mask); +void alSetBeepSevrChan(CLINK *link,int sevr); +void alSetBeepSevrGroup(GLINK *link,int sevr); +void alRemoveNoAck1HrTimerGroup(GLINK *glink); +void alRemoveNoAck1HrTimerChan(CLINK *clink); + + +/******************************************************************** + alLog.c function prototypes +*********************************************************************/ + +void alLogAlarmMessage(time_t *ptimeofdayAlarm,int messageCode,CLINK* clink,const char *fmt,...); +void alLogOpModMessage(int messageCode,GCLINK* clink,const char *fmt,...); +void alLogOpModAckMessage(int messageCode,GCLINK* gclink,const char* fmt,...); +void alLog2DBAckChan (char *name); +void alLogNotSaveStart(int not_save_time); +void alLogNotSaveFinish(); +void alLog2DBMask (char *name); + +#ifdef CMLOG +void alCMLOGconnect(void); +void alCMLOGdisconnect(void); +#endif + +/******************************************************************** + alView.c function prototypes +*********************************************************************/ + +int alViewAdjustGroupW( GLINK *glink, int (*viewFilter)()); +int alViewAdjustTreeW( GLINK *glink, int command, int (*viewFilter)()); +GCLINK *alViewNextTreeW( GLINK *glink, int *plinkType); +GCLINK *alViewNextGroupW( GCLINK *link, int *plinkType); +GCLINK *alViewNthTreeW( GLINK *glinkStart, int *plinkType, int n); +GCLINK *alViewNthGroupW( GLINK *link, int *plinkType, int n); +int alViewMaxSevrNGroupW( GCLINK *linkStart, int n); +int alViewMaxSevrNTreeW( GLINK *glinkStart, int n); + + +/******************************************************************** + awAct.c function prototypes +*********************************************************************/ + +Widget actCreateMenu( Widget parent, XtPointer user_data); + + +/******************************************************************** + awEdit.c function prototypes +*********************************************************************/ + +void editUndoSet( GCLINK *link, int linkType, GCLINK *configLink, +int command, int delete); +void editUndoGet( GCLINK **plink, int *plinkType, +GCLINK **pconfigLink); +int editUndoGetCommand(void); +void editClipboardGet( GCLINK **plink, int *plinkType); +void editClipboardSet( GCLINK *link, int linkType); +void editCutLink( ALINK *area, GCLINK *link, int linkType); +void editInsertFile( char *filename, ALINK *area); +void editPasteLink( ALINK *area, GCLINK *newLink, int linkType); + +/******************************************************************** + awAlh.c function prototypes +*********************************************************************/ + +Widget alhCreateMenu( Widget parent, XtPointer user_data); +void awRowWidgets( struct anyLine *gline, void *area); +void awUpdateRowWidgets( struct anyLine *line); + +/******************************************************************** + line.c function prototypes +*********************************************************************/ + +void awGetMaskString( int mask[ALARM_NMASK], char *s); +struct anyLine *awAllocLine(void); +void awUpdateChanLine( struct anyLine *chanLine); +void awUpdateGroupLine( struct anyLine *groupLine); +void initLine( struct anyLine *line); +void initializeLines( SNODE *lines); + +/******************************************************************** + current.c function prototypes +*********************************************************************/ + +void currentAlarmHistoryWindow( ALINK *area, Widget menuButton); +void updateCurrentAlarmString( ALINK *area, time_t *ptimeofday, +char *name, char value[], int stat,int sev); +void updateCurrentAlarmWindow( ALINK *area); +void resetCurrentAlarmWindow(ALINK *area); + +/******************************************************************** + showmask.c function prototypes +*********************************************************************/ + +void forceMaskShowDialog(ALINK *area,Widget menuButton); +void forceMaskUpdateDialog(ALINK *area); + +/******************************************************************** + force.c function prototypes +*********************************************************************/ + +void forcePVShowDialog(ALINK *area,Widget menuButton); +void forcePVUpdateDialog(ALINK *area); +void alForcePVValueEvent(void *usr,double value); +void alForcePVDelete(FORCEPV**); +FORCEPV* alForcePVCopy(FORCEPV*); +void alForcePVClearCA(FORCEPV*); +void alForcePVSetNotConnected(FORCEPV*,char*); + +/******************************************************************** + alCA.c function prototypes +*********************************************************************/ + +void alCaPend(double sec); +short alCaIsConnected(chid chid); +void alCaFlushIo(void); +void alCaInit(void); +void alCaPoll(void); +void alCaStop(void); +void alCaConnectChannel(char *name,chid *pchid,void *puser); +void alCaConnectForcePV(char *name,chid *pchid,void *puser); +void alCaConnectSevrPV(char *name,chid *pchid,void *puser); +void alCaConnectAckPV(char *name,chid *pchid,void *puser); +void alCaConnectHeartbeatPV(char *name,chid *pchid,void *puser); +void alCaClearChannel(chid *pchid); +void alCaClearEvent(evid *pevid); +void alCaAddEvent(chid chid,evid *pevid,void *clink); +void alCaAddForcePVEvent(chid chid,void *link,evid *pevid); +void alCaPutGblAck(chid chid,short *psevr); +void alCaPutSevrValue(chid chid,short *psevr); +void alCaPutHeartbeatValue(chid chid,short *value); +void alCaPutGblAckT(chid chid, short *pstate); +void alCaPutAckValue(chid chid, short *psevr); +void getDescriptionRecord(char *name,char *description,chid descriptionFieldCaId); + +/******************************************************************** + alCaCommon.c function prototypes +*********************************************************************/ +void alCaCancel(struct mainGroup *pmainGroup); +void registerCA(void *dummy, int fd, int opened); +void alUpdateAreas(); +void alSetNotConnected(struct mainGroup *pmainGroup); +void alPutGblAckT(struct mainGroup *pmainGroup); + +/******************************************************************** + alConfig.c function prototypes +*********************************************************************/ + +void alGetConfig( struct mainGroup * pmainGroup, char *filename, int caConnect); +void alCreateConfig( struct mainGroup * pmainGroup); +void alPrintConfig(FILE *fw,struct mainGroup *pmainGroup); +void alWriteConfig( char *filename, struct mainGroup *pmainGroup); +void addNewSevrCommand(ELLLIST *pList,char *str); +void addNewStatCommand(ELLLIST *pList,char *str); +void removeSevrCommandList(ELLLIST *pList); +void removeStatCommandList(ELLLIST *pList); +void copySevrCommandList(ELLLIST *pListOld,ELLLIST *pListNew); +void copyStatCommandList(ELLLIST *pListOld,ELLLIST *pListNew); +void spawnSevrCommandList(ELLLIST *pList,int sev,int sevr_prev); +void spawnStatCommandList(ELLLIST *pList,int sev,int sevr_prev); +void getStringSevrCommandList(ELLLIST *pList,char **pstr); +void getStringStatCommandList(ELLLIST *pList,char **pstr); + +/******************************************************************** + scroll.c function prototypes +*********************************************************************/ + +void fileViewWindow( Widget w, int option, Widget menuButton); +void updateLog( int fileIndex, char *string); +void updateAlarmLog( int fileIndex, char *string); +void browser_fileViewWindow(Widget w,int option,Widget menuButton); + +/******************************************************************** + testalarm.c function prototypes +*********************************************************************/ + +void done_dialog( Widget w, Widget dialog, XmAnyCallbackStruct *call_data); +void hide_dialog( Widget w, Widget dialog, XmAnyCallbackStruct *call_data); +Widget createGetTestAlarm_dialog( Widget parent, XtPointer userData); +void show_dialog( Widget w, Widget dialog, XmAnyCallbackStruct *call_data); + +/******************************************************************** + mask.c function prototypes +*********************************************************************/ + +void maskShowDialog(ALINK *area,Widget menuButton); +void maskUpdateDialog(ALINK *area); + +/******************************************************************** + help.c function prototypes +*********************************************************************/ + +void xs_help_callback( Widget w, char *str[], void *call_data); +void helpCallback( Widget w, int item, XmAnyCallbackStruct *cbs); + +/******************************************************************** + beepSevr.c function prototypes +*********************************************************************/ + +void beepSevrUpdateDialog(ALINK *area); +void beepSevrShowDialog(ALINK *area, Widget widget); + +/******************************************************************** + noAck.c function prototypes +*********************************************************************/ + +void noAckUpdateDialog(ALINK *area); +void noAckShowDialog(ALINK *area, Widget widget); + +/******************************************************************** + property.c function prototypes +*********************************************************************/ + +void propUpdateDialog(ALINK *area); +void propShowDialog(ALINK *area, Widget widget); +void propUndo(void *area); + + +/******************************************************************** + os//alAudio.c function prototypes +*********************************************************************/ + +void alBeep(Display *displayBB); + +/******************************************************************** + heartbeat.c function prototypes +*********************************************************************/ + +void alHeartbeatStart(void* data); +void alHeartbeatStop(void* data); +void alHeartbeatPVRemove(struct mainGroup *pmainGroup); +void alHeartbeatPVAdd(struct mainGroup *pmainGroup,char* name,float rate,short value); + + + + +#endif /* INCaxh */ +/* alCaCommon.c */ + diff --git a/axArea.c b/axArea.c new file mode 100644 index 0000000..3eca8df --- /dev/null +++ b/axArea.c @@ -0,0 +1,1008 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* axArea.c */ + +/************************DESCRIPTION*********************************** + Routines for main window widgets +**********************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cadef.h" +#include "alarm.h" +#include "ALH.bit" + +#include "alh.h" +#include "line.h" +#include "axArea.h" +#include "sllLib.h" +#include "ax.h" + +Pixmap ALH_pixmap; +char *silenceString[] = {"Off","On"}; +const char *executionStateString[] = {"Active","Passive"}; +char *disabledForcePVCountString[] = {" ","Disabled forcePVs:"}; + +/* global variables */ +extern int _global_flag; +extern int _passive_flag; +extern int toBeConnectedCount; +extern int DEBUG; +extern SLIST *areaList; +extern struct setup psetup; +extern Display *display; +extern char *alhAlarmSeverityString[]; +extern int _main_window_flag; +extern int (*default_display_filter)(GCLINK *); +extern const char *executionModeString[]; + +ALINK *alhArea; + +/* forward definitions */ +static ALINK *setupArea( ALINK *areaOld); +static void scale_callback(Widget widget,ALINK *area,XmScaleCallbackStruct *cbs); + + +/****************************************************** + buildPulldownMenu - Generic menu creation +******************************************************/ +Widget buildPulldownMenu( Widget parent, char *menu_title, char menu_mnemonic, +int tearOff, MenuItem *items, XtPointer user_data) +{ + Widget PullDown, cascade, widget; + int i; + XmString str; + WidgetClass *xmclass[] = { &xmPushButtonGadgetClass, &xmSeparatorGadgetClass, &xmToggleButtonGadgetClass }; + + /* Pulldown menus are built from cascade buttons, so this function + * also includes pullright menus. Create the menu, the cascade button + * that owns the menu, and then the submenu items. + */ + PullDown = XmCreatePulldownMenu(parent, "_pulldown", NULL, 0); + + str = XmStringCreateSimple(menu_title); + cascade = XtVaCreateManagedWidget(menu_title, + xmCascadeButtonGadgetClass, parent, + XmNsubMenuId, PullDown, + XmNlabelString, str, + XmNmnemonic, menu_mnemonic, + (XtPointer)NULL); + XmStringFree(str); + +# if 0 /* DO NOT Use TEAROFF FEATURE. TORNOFF MENUS CANNOT BE CLOSED */ +#if XmVersion && XmVersion >= 1002 + if (tearOff){ + /* Enable pulldown menu tearoff functionality */ + XtVaSetValues(PullDown, XmNtearOffModel, XmTEAR_OFF_ENABLED, NULL); + } +#endif +#endif + + /* Now add the menu items */ + for (i = 0; items[i].label != NULL; i++) { + /* If subitems exist, create the pull-right menu by calling this + * function recursively. Since the function returns a cascade + * button, the widget returned is used.. + */ + if (items[i].subitems) + widget = buildPulldownMenu(PullDown, + items[i].label, items[i].mnemonic, FALSE, items[i].subitems, user_data); + else { + widget = XtVaCreateManagedWidget(items[i].label, + *xmclass[items[i].class], PullDown, + XmNuserData, user_data, + NULL); + + /* Make spacing of toggle button items the same as pushButtons */ + if (xmclass[items[i].class] == &xmToggleButtonWidgetClass || + xmclass[items[i].class] == &xmToggleButtonGadgetClass) + XtVaSetValues(widget, XmNmarginHeight, 1, NULL); + + /* Set initial state of of toggle button items */ + if (xmclass[items[i].class] == &xmToggleButtonWidgetClass || + xmclass[items[i].class] == &xmToggleButtonGadgetClass) + XmToggleButtonSetState(widget,(Boolean)items[i].initial_state,FALSE); + } + /* Whether the item is a real item or a cascade button with a + * menu, it can still have a mnemonic. */ + if (items[i].mnemonic) + XtVaSetValues(widget, XmNmnemonic, items[i].mnemonic, NULL); + /* any item can have an accelerator, except cascade menus. But, + * we don't worry about that; we know better in our declarations. */ + if (items[i].accelerator) { + str = XmStringCreateSimple(items[i].accel_text); + XtVaSetValues(widget, + XmNaccelerator, items[i].accelerator, + XmNacceleratorText, str, + NULL); + XmStringFree(str); + } + /* again, anyone can have a callback -- however, this is an + * activate-callback. This may not be appropriate for all items. + */ + if (items[i].callback) + XtAddCallback(widget, + (xmclass[items[i].class] == &xmToggleButtonWidgetClass || + xmclass[items[i].class] == &xmToggleButtonGadgetClass)? + XmNvalueChangedCallback : /* ToggleButton class */ + XmNactivateCallback, /* PushButton class */ + items[i].callback, items[i].callback_data); + } + return cascade; +} + +/*************************************************** + setupConfig - Setup area with new config.file +****************************************************/ +void setupConfig(char *filename,int program,ALINK *areaOld) +{ + ALINK *area; + struct mainGroup *pmainGroup = NULL; + XmString str; + SNODE *proot; + static int firstTime = TRUE; + int beepSevrOld; + int holdToBeConnectedCount; + + /* initialize channel access */ + if (program == ALH) { + if (firstTime) { + firstTime = FALSE; + alCaInit(); + } + } + + /* create main group */ + pmainGroup = alAllocMainGroup(); + if (!pmainGroup ) { + if (areaOld) + createDialog(areaOld->form_main,XmDIALOG_ERROR, + "mainGroup allocation error: ",filename); + return; + } + + /* reinitialize beep severity */ + beepSevrOld = psetup.beepSevr; + psetup.beepSevr = 1; + + /* Read the config file or create a minimal config file */ + if (filename[0] != '\0'){ + if ( program == ALH) { + + toBeConnectedCount =0; + alLogOpModMessage(0,0, "Setup Config File : %s",filename); + alGetConfig(pmainGroup,filename,CA_CONNECT_YES); + + /* now lets give the connection layer a little time + * to establish communications */ + holdToBeConnectedCount = toBeConnectedCount; + while (TRUE) { + alCaPend(1.0); + if (toBeConnectedCount == holdToBeConnectedCount) break; + holdToBeConnectedCount = toBeConnectedCount; + } + + alSetNotConnected(pmainGroup); + alPutGblAckT(pmainGroup); + } + else { + /* Log new configfile filename */ + alLogOpModMessage(0,0, "Setup Config File : %s",filename); + alGetConfig(pmainGroup,filename,CA_CONNECT_NO); + } + if (sllFirst(pmainGroup)) strcpy(psetup.configFile,filename); + } else{ + if (program == ACT) alCreateConfig(pmainGroup); + else { + if (areaOld) { + psetup.beepSevr = beepSevrOld; + areaOld->managed = TRUE; + errMsg ("ALH Error: Invalid config file: %s\n",filename); + return; + } + } + } + if ( sllFirst(pmainGroup)) { + + proot = sllFirst(pmainGroup); + + /* initialize unused area */ + area = setupArea(areaOld); + + /* initialize subWindow create/modify line routines */ + setLineRoutine(area,area->treeWindow,program); + setLineRoutine(area,area->groupWindow,program); + + pmainGroup->area = area; + area->programId = program; + area->pmainGroup = pmainGroup; + area->changed = FALSE; + + /* activate runtime window for ALH */ + if (program == ALH){ + area->blinkString = alAlarmGroupName((GLINK *)proot); + alHighestSystemSeverity((GLINK *)proot); + if (_main_window_flag) showMainWindow(area); + else createRuntimeWindow(area); + } + + /* create/display main window for ACT */ + if (program == ACT ) showMainWindow(area); + + createConfigDisplay(area,EXPANDCOLLAPSE1); + + if (program == ALH ) alhArea = area; + + area->managed = TRUE; + + /* update filename string on main window */ + if (area->label_filename){ + str = XmStringCreateSimple(psetup.configFile); + XtVaSetValues(area->label_filename, + XmNlabelString, str, + NULL); + XmStringFree(str); + } + + /* update dialog windows */ + axUpdateDialogs(area); + + /* unmap dialog */ +/* + createDialog(0,0," "," "); +*/ + + } else { + free(pmainGroup); + if (areaOld) { + psetup.beepSevr = beepSevrOld; + areaOld->managed = TRUE; + errMsg ("ALH Error: Invalid config file: %s\n",filename); + } else { + errMsg ("ALH Error: Invalid config file: %s\n",filename); + exit_quit(NULL, NULL, NULL); + } + } + return; +} + +/****************************************************** + markActiveWidget - Mark active widget border +******************************************************/ +void markActiveWidget(ALINK *area,Widget newWidget) +{ + + /* NOTE: this routine not implemented yet. Border looks YUK! + + if (area->selectionWidget == newWidget ) return; + + if (area->selectionWidget) { + XtVaSetValues(area->selectionWidget, + XmNborderWidth, 0, + NULL); + } + + if (newWidget) { + XtVaSetValues(newWidget, + XmNborderWidth, 1, + NULL); + } + + area->selectionWidget = newWidget; + */ +} + +/****************************************************** + setupArea - Initialize an area +******************************************************/ + +static ALINK *setupArea(ALINK *areaOld) +{ + ALINK *area; + SNODE *proot; + + if (!areaOld){ + /* create work area linked list */ + if (!areaList){ + areaList = (SLIST *)calloc(1,sizeof(SLIST)); + sllInit(areaList); + } + + /* find an unused existing work area */ + area = (ALINK *)sllFirst(areaList); + while (area){ + if (area->managed == FALSE || area->pmainGroup == NULL) break; + area = (ALINK *)sllNext(area); + } + } else area = areaOld; + + /* reinitialize an unused existing work area */ + if (area){ + + area->managed = FALSE; + + /* unmark selected widgets */ + markSelectedWidget(area->treeWindow,NULL); + markSelectedWidget(area->groupWindow,NULL); + markActiveWidget(area,0); + + /* Delete the current config */ + if (area->pmainGroup){ + + + /* cancel channel access */ + alCaCancel(area->pmainGroup); + + proot = sllFirst(area->pmainGroup); + if (proot) alDeleteGroup((GLINK *)proot); + + alHeartbeatPVRemove(area->pmainGroup); + free(area->pmainGroup); + area->pmainGroup = NULL; + } + + /* or create a new work area */ + } else { + area=(ALINK *)calloc(1,sizeof(ALINK)); + sllAdd(areaList,(SNODE *)area); + + /* Set alarm filter to default value */ + area->viewFilter = default_display_filter; + + area->blinkString = NULL; + + area->runtimeToplevel = NULL; + area->treeWindow = createSubWindow(area); + area->groupWindow = createSubWindow(area); + } + + /* Reset count of disabled forcePVs */ + area->disabledForcePVCount = 0; + + /* Reset data for Current alarm window */ + resetCurrentAlarmWindow(area); + + /* Make NULL the selected group for Area */ + area->selectionLink = NULL; + + /* initialize the subWindows */ + initializeSubWindow(area->treeWindow); + initializeSubWindow(area->groupWindow); + + return area; +} + +/****************************************************** + createMainWindowWidgets - Create area Main Window widgets +******************************************************/ +void createMainWindowWidgets(ALINK *area) +{ + char actTitle[] = "Alarm Configuration Tool"; + char alhTitle[] = "Alarm Handler"; + char execMode[50] = "Execution Status: "; + XmString str; + char *app_name; + char *title_str; + int len = 0; + Widget label_executionMode; + + if (area->toplevel) return; + + /* create toplevel shell */ + app_name = (char*) calloc(1,strlen(programName)+6); + strcpy(app_name, programName); + strcat(app_name, "-main"); + + area->toplevel = XtAppCreateShell(app_name, programName, + applicationShellWidgetClass, display, NULL, 0); + + free(app_name); + + if (area->blinkString) len = strlen(area->blinkString); + if (area->programId == ACT){ + title_str = (char*) calloc(1,strlen(actTitle)+len+3); + strcpy(title_str, actTitle); + } else { + title_str = (char*) calloc(1,strlen(alhTitle)+len+3); + strcpy(title_str, alhTitle); + } + if (area->blinkString){ + strcat(title_str, ": "); + strcat(title_str, area->blinkString); + } + + XtVaSetValues(area->toplevel, + XmNtitle, title_str, + XmNiconName, area->blinkString, + NULL); + + free(title_str); + + /* Create form_main for toplevel */ + area->form_main = XtVaCreateManagedWidget("form_main", + xmFormWidgetClass, area->toplevel, + XmNuserData, (XtPointer)area, + NULL); + + pixelData(area->form_main); + + if (!ALH_pixmap) axMakePixmap(area->form_main); + +#ifndef WIN32 + XtVaSetValues(area->toplevel, XmNiconPixmap, ALH_pixmap, NULL); +#endif + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(area->toplevel, + XmNdeleteResponse, XmDO_NOTHING, + NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(area->form_main), + "WM_DELETE_WINDOW", False); + if (_main_window_flag) + XmAddWMProtocolCallback(area->toplevel,WM_DELETE_WINDOW, + (XtCallbackProc) exit_quit, (XtPointer) area); + else + XmAddWMProtocolCallback(area->toplevel,WM_DELETE_WINDOW, + (XtCallbackProc) unmapArea_callback, (XtPointer) area->form_main); + } + + /* Create MenuBar */ + if (area->programId == ACT){ + area->menubar = actCreateMenu(area->form_main, (XtPointer)area); + } else { + area->menubar = alhCreateMenu(area->form_main, (XtPointer)area); + } + + /* Create message Area Form */ + area->messageArea = XtVaCreateWidget("message_area", + xmFormWidgetClass, area->form_main, + XmNallowOverlap, FALSE, + XmNbottomAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + /* Create scale in the MessageArea to change display split */ + area->scale = XtVaCreateManagedWidget("scale", + xmScaleWidgetClass, area->messageArea, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNorientation, XmHORIZONTAL, + XmNuserData, (XtPointer)area, + (XtPointer)NULL); + + /* Add scale valueChanged Callback */ + XtAddCallback(area->scale, XmNvalueChangedCallback, (XtCallbackProc)scale_callback, area); + + /* Add scale drag Callback */ + XtAddCallback(area->scale, XmNdragCallback, (XtCallbackProc)scale_callback, area); + + /* Create execution mode indicator label for the messageArea */ + strcat(execMode,executionModeString[_global_flag]); + strcat(execMode," "); + strcat(execMode,executionStateString[_passive_flag]); + label_executionMode = XtVaCreateManagedWidget( + execMode, + xmLabelGadgetClass, area->messageArea, + XmNmarginHeight, 3, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->scale, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 1, + (XtPointer)NULL); + + /* Create group alarm decoder label for the messageArea */ + area->label_mask = XtVaCreateManagedWidget( + "Mask : H=noAck 1hr timer", + xmLabelGadgetClass, area->messageArea, + XmNmarginHeight, 3, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, label_executionMode, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 1, + NULL); + + /* Create group alarm decoder label for the messageArea */ + area->label_groupAlarm = XtVaCreateManagedWidget( + "Group Alarm Counts: (ERROR,INVALID,MAJOR,MINOR,NOALARM)", + xmLabelGadgetClass, area->messageArea, + XmNmarginHeight, 3, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->label_mask, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 1, + NULL); + + /* Create filenameTitle label for the messageArea */ + area->label_channelAlarm = XtVaCreateManagedWidget( + "Channel Alarm Data: ,", + xmLabelGadgetClass, area->messageArea, + XmNmarginHeight, 3, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->label_groupAlarm, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 1, + NULL); + + /* Create filenameTitle label for the messageArea */ + area->label_filenameTitle = XtVaCreateManagedWidget("Filename: ", + xmLabelGadgetClass, area->messageArea, + XmNmarginHeight, 3, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->label_channelAlarm, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 1, + NULL); + + + /* Create filename label for the messageArea */ + str = XmStringCreateSimple(psetup.configFile); + area->label_filename = XtVaCreateManagedWidget("label_filename", + xmLabelGadgetClass, area->messageArea, + XmNlabelString, str, + XmNshadowThickness, 2, + XmNalignment, XmALIGNMENT_BEGINNING, + /* + xmTextWidgetClass, area->messageArea, + XmNeditable, FALSE, + XmNmarginHeight, 0, + XmNresizeWidth, FALSE, + XmNvalue, psetup.configFile, + XmNcursorPositionVisible, FALSE, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + */ + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->label_channelAlarm, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, area->label_filenameTitle, + XmNrightAttachment, XmATTACH_FORM, + NULL); + XmStringFree(str); + + + /* Create a Silence One Hour Toggle Button in the messageArea */ + area->silenceOneHour = XtVaCreateManagedWidget("SilenceOneHour", + xmToggleButtonGadgetClass, area->messageArea, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->scale, + XmNrightAttachment, XmATTACH_FORM, + XmNuserData, (XtPointer)area, + NULL); + + /* Create a Silence Current Toggle Button in the messageArea */ + area->silenceCurrent = XtVaCreateManagedWidget("SilenceCurrent", + xmToggleButtonGadgetClass, area->messageArea, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->silenceOneHour, + XmNrightAttachment, XmATTACH_FORM, + XmNuserData, (XtPointer)area, + NULL); + + /* Create SilenceForever string for the messageArea */ + str = XmStringCreateSimple(silenceString[psetup.silenceForever]); + area->silenceForever = XtVaCreateManagedWidget("silenceForever", + xmLabelGadgetClass, area->messageArea, + XmNlabelString, str, + XmNshadowThickness, 2, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->silenceCurrent, + XmNrightAttachment, XmATTACH_FORM, + NULL); + XmStringFree(str); + + /* Create SilenceForeverLabel string for the messageArea */ + str = XmStringCreateSimple("Silence Forever: "); + area->silenceForeverLabel = XtVaCreateManagedWidget("silenceForeverLabel", + xmLabelGadgetClass, area->messageArea, + XmNshadowThickness, 2, + XmNlabelString, str, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->silenceCurrent, + XmNrightAttachment, XmATTACH_WIDGET, + XmNrightWidget, area->silenceForever, + NULL); + XmStringFree(str); + + /* Create BeepSeverity string for the messageArea */ + str = XmStringCreateSimple(alhAlarmSeverityString[psetup.beepSevr]); + area->beepSeverity = XtVaCreateManagedWidget("beepSeverity", + xmLabelGadgetClass, area->messageArea, + XmNlabelString, str, + XmNshadowThickness, 2, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->silenceForever, + XmNrightAttachment, XmATTACH_FORM, + NULL); + XmStringFree(str); + + /* Create BeepSeverityLabel string for the messageArea */ + str = XmStringCreateSimple("ALH Beep Severity:"); + area->beepSeverityLabel = XtVaCreateManagedWidget("beepSeverityLabel", + xmLabelGadgetClass, area->messageArea, + XmNshadowThickness, 2, + XmNlabelString, str, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->silenceForever, + XmNrightAttachment, XmATTACH_WIDGET, + XmNrightWidget, area->beepSeverity, + NULL); + XmStringFree(str); + + XtAddCallback(area->silenceOneHour, XmNvalueChangedCallback, + (XtCallbackProc)silenceOneHour_callback,area); + + XtAddCallback(area->silenceCurrent, XmNvalueChangedCallback, + (XtCallbackProc)silenceCurrent_callback,area); + + /* Create Disabled ForcePV Count string for the messageArea */ + str = XmStringCreateSimple(disabledForcePVCountString[0]); + area->disabledForcePVCountLabel = XtVaCreateManagedWidget("disabledForcePVCountLabel", + xmLabelGadgetClass, area->messageArea, + XmNshadowThickness, 2, + XmNlabelString, str, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->beepSeverity, + XmNrightAttachment, XmATTACH_FORM, + NULL); + XmStringFree(str); + + /* manage the message area */ + XtManageChild(area->messageArea); + + /* Create a Form for the treeWindow */ + area->treeWindowForm = XtVaCreateManagedWidget("treeForm", + xmFormWidgetClass, area->form_main, + XmNborderWidth, 1, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->menubar, + XmNbottomAttachment, XmATTACH_WIDGET, + XmNbottomWidget, area->messageArea, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + NULL); + + XtAddEventHandler(area->form_main, StructureNotifyMask, + FALSE, (XtEventHandler)exposeResizeCallback, (XtPointer *)area->treeWindow); + + createSubWindowWidgets(area->treeWindow,area->treeWindowForm); + + /* Create a Form for the groupWindow */ + area->groupWindowForm = XtVaCreateManagedWidget("groupForm", + xmFormWidgetClass, area->form_main, + XmNborderWidth, 1, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, area->menubar, + XmNbottomAttachment, XmATTACH_WIDGET, + XmNbottomWidget, area->messageArea, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 50, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtAddEventHandler(area->form_main, StructureNotifyMask, + FALSE, (XtEventHandler)exposeResizeCallback, (XtPointer *)area->groupWindow); + + createSubWindowWidgets(area->groupWindow,area->groupWindowForm); + +} + +/****************************************************** + createMainWindow_callback +******************************************************/ +void showMainWindow(ALINK *area) +{ + if (area->toplevel == 0){ + area->mapped = FALSE; + createMainWindowWidgets(area); + XtRealizeWidget(area->toplevel); + } + if (area->mapped == FALSE){ + XMapWindow(XtDisplay(area->toplevel),XtWindow(area->toplevel)); + area->mapped = TRUE; + redraw(area->treeWindow,0); + + /* mark first line as treeWindow selection */ + defaultTreeSelection(area); + } + else { + XRaiseWindow(XtDisplay(area->toplevel), XtWindow(area->toplevel)); + redraw(area->treeWindow,0); + } +} + +/*************************************************** + isTreeWindow - Returns TRUE if area is a treeWindow +****************************************************/ +int isTreeWindow(ALINK *area,void * subWindow) +{ + if (area->treeWindow == subWindow ) return(TRUE); + else return(FALSE); +} + +/****************************************************** + unmapArea_callback +******************************************************/ +void unmapArea_callback(Widget main,Widget w,XmAnyCallbackStruct *cbs) +{ + ALINK *area; + + XtVaGetValues(w, XmNuserData, &area, NULL); + + XUnmapWindow(XtDisplay(main),XtWindow(main)); + + area->mapped = FALSE; + +} +/****************************************************** + scale_callback - Scale moved callback +******************************************************/ +static void scale_callback(Widget widget,ALINK *area,XmScaleCallbackStruct *cbs) +{ + int value; + + value = Mmin(95,Mmax(5,cbs->value)); + + XtVaSetValues(area->groupWindowForm, + XmNleftPosition, value, + NULL); + XtVaSetValues(area->treeWindowForm, + XmNrightPosition, value, + NULL); +} + +/*************************************************** + markSelectionArea - Set area selection values +****************************************************/ +void markSelectionArea(ALINK *area,struct anyLine *line) +{ + /* Save selection data */ + if (!line){ + area->selectionLink = 0; + area->selectionType = 0; + area->selectionWindow = 0; + } else { + area->selectionLink = line->link; + area->selectionType = line->linkType; + area->selectionWindow = (void *)line->pwindow; + } + + return; +} + +/*************************************************** + axMakePixmap +****************************************************/ +void axMakePixmap(Widget w) +{ + Pixel fg,bg; + int depth; + + /* + * create icon pixmap + */ + if (!ALH_pixmap){ + + /* + * get colors and depth + */ + XtVaGetValues(w, + XmNforeground, &fg, + XmNbackground, &bg, + XmNdepth, &depth, + NULL); + + ALH_pixmap = XCreatePixmapFromBitmapData(XtDisplay(w), + RootWindowOfScreen(XtScreen(w)), + (char *)AH_bits,AH_width,AH_height,fg,bg,depth); + + } + return; +} + +/*************************************************** + changeBeepSeverityText +****************************************************/ +void changeBeepSeverityText(ALINK *area) +{ + XmString str; + + if (area->beepSeverity) { + str = XmStringCreateSimple(alhAlarmSeverityString[psetup.beepSevr]); + XtVaSetValues(area->beepSeverity, + XmNlabelString, str, + NULL); + XmStringFree(str); + } +} + +/*************************************************** + changeSilenceForeverText +****************************************************/ +void changeSilenceForeverText(ALINK *area) +{ + XmString str; + + if (area->silenceForever) { + str = XmStringCreateSimple(silenceString[psetup.silenceForever]); + XtVaSetValues(area->silenceForever, + XmNlabelString, str, + NULL); + XmStringFree(str); + } +} + +/*************************************************** + updateDisabledForcePVCount +****************************************************/ +void updateDisabledForcePVCount(ALINK *area,int value) +{ + area->disabledForcePVCount += value; +} + +/*************************************************** + changeDisabledForcePVText +****************************************************/ +void changeDisabledForcePVText(ALINK *area) +{ + XmString str; + char buff[24]; + + if (area->disabledForcePVCountLabel) { + if (area->disabledForcePVCount) { + sprintf(buff,"%-.18s %4.4d", + disabledForcePVCountString[1],area->disabledForcePVCount); + } else sprintf(buff,"%-.18s",disabledForcePVCountString[0]); + str = XmStringCreateSimple(buff); + XtVaSetValues(area->disabledForcePVCountLabel, + XmNlabelString, str, + NULL); + XmStringFree(str); + } +} + +/****************************************************** + axUpdateDialogs +******************************************************/ +void axUpdateDialogs(ALINK *area) +{ + /* update beepSeverity string on main window */ + changeBeepSeverityText(area); + + /* update silenceForever string on main window */ + changeSilenceForeverText(area); + + /* update disabledForcePVCount string on main window */ + changeDisabledForcePVText(area); + + /* update property sheet window if it is displayed */ + propUpdateDialog(area); + + /* update force mask window if it is displayed */ + forceMaskUpdateDialog(area); + + /* update forcePV window if it is displayed */ + forcePVUpdateDialog(area); + + /* update force mask window if it is displayed */ + maskUpdateDialog(area); + + /* update set beep severity window if it is displayed */ + beepSevrUpdateDialog(area); + + /* update noAck for one hour window if it is displayed */ + noAckUpdateDialog(area); + +} + +/*************************************************** + getSelectionLinkArea +****************************************************/ +void *getSelectionLinkArea(ALINK *area) +{ + return area->selectionLink; +} + +/*************************************************** + getSelectionLinkTypeArea +****************************************************/ +int getSelectionLinkTypeArea(ALINK *area) +{ + return area->selectionType; +} + + +/****************************************************** + CreateActionButtons +******************************************************/ +Widget createActionButtons(Widget parent,ActionAreaItem *actions, +int num_buttons) +{ + Widget mask_sheet, widget; + int i; + + mask_sheet = XtVaCreateWidget("mask_sheet", xmFormWidgetClass, parent, + XmNfractionBase, TIGHTNESS*num_buttons - 1, + XmNleftOffset, 10, + XmNrightOffset, 10, + NULL); + + for (i = 0; i < num_buttons; i++) { + widget = XtVaCreateManagedWidget(actions[i].label, + xmPushButtonWidgetClass, mask_sheet, + XmNmarginHeight, 0, + XmNleftAttachment, i? XmATTACH_POSITION : XmATTACH_FORM, + XmNleftPosition, TIGHTNESS*i, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNrightAttachment, + i != num_buttons-1? XmATTACH_POSITION : XmATTACH_FORM, + XmNrightPosition, TIGHTNESS*i + (TIGHTNESS-1), + XmNshowAsDefault, i == 2, + XmNdefaultButtonShadowThickness, 1, + (XtPointer)NULL); + if (actions[i].callback) + XtAddCallback(widget, XmNactivateCallback, + actions[i].callback, actions[i].data); + if (i == 2) { + /* Set the mask_sheet's default button to the third widget + * created (or, make the index a parameter to the function + * or have it be part of the data structure). Also, set the + * pane window constraint for max and min heights so this + * particular pane in the PanedWindow is not resizable. + */ + Dimension height, h; + XtVaGetValues(mask_sheet, XmNmarginHeight, &h, NULL); + XtVaGetValues(widget, XmNheight, &height, NULL); + height += 2 * h; + XtVaSetValues(mask_sheet, + XmNdefaultButton, widget, + XmNpaneMaximum, height, + XmNpaneMinimum, height, + NULL); + } + } + + XtManageChild(mask_sheet); + + return mask_sheet; +} diff --git a/axArea.h b/axArea.h new file mode 100644 index 0000000..700a7df --- /dev/null +++ b/axArea.h @@ -0,0 +1,114 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* axArea.h */ + +/************************DESCRIPTION*********************************** + Area structure definitions +**********************************************************************/ + +#ifndef INCaxAreah +#define INCaxAreah + +#include +#include +#include + +#include "sllLib.h" + +#define PushButtonGadgetClass 0 +#define SeparatorGadgetClass 1 +#define ToggleButtonGadgetClass 2 + +typedef struct areaLink{ + SNODE node; + int mapped; + int managed; + int programId; + /* area widget info */ + /* runtime window widgets */ + Widget runtimeToplevel; + Widget runtimeForm; + Widget blinkButton; + + /* main window widgets */ + Widget toplevel; + Widget icon; + Widget form_main; + Widget menubar; + Widget messageArea; + Widget scale; + Widget label_filename; + Widget label_groupAlarm; + Widget label_channelAlarm; + Widget label_mask; + Widget silenceOneHour; + Widget silenceCurrent; + Widget silenceForever; + Widget silenceForeverLabel; + Widget beepSeverity; + Widget beepSeverityLabel; + Widget disabledForcePVCountLabel; + Widget label_filenameTitle; + Widget treeWindowForm; + Widget groupWindowForm; + /* ----- Config info ----- */ + struct mainGroup *pmainGroup; + int changed; + char *blinkString; + /* ----- setup info ----- */ + int (* viewFilter)(); + int beepCondition; + int disabledForcePVCount; + char *configFile; + char *alarmlogFile; + char *opmodFile; + char *histFile; + /* ----- subWindow inf ----- */ + void *treeWindow; + void *groupWindow; + void *propWindow; + void *forceMaskWindow; + void *forcePVWindow; + void *maskWindow; + void *beepSevrWindow; + void *noAckWindow; + /* ----- Current Selection groupLine info ----- */ + void *selectionWindow; + void *selectionLink; + int selectionType; + Widget selectionWidget; + /* ----- Current alarm window info ----- */ + int currentAlarmIndex; + Widget currentAlarmForm; + Widget currentAlarm[10]; + char currentAlarmString[10][128]; + int w; + int h; +} ALINK; + +typedef struct _menu_item { + char *label; /* the label for the item */ + int class; /* pushbutton, label, separator... */ + char mnemonic; /* mnemonic; NULL if none */ + char *accelerator; /* accelerator; NULL if none */ + char *accel_text; /* to be converted to compound string */ + void (*callback)( Widget,XtPointer,XtPointer); /* routine to call; NULL if note */ + XtPointer callback_data; /* client_data for callback() */ + struct _menu_item *subitems; /* pullright menu items, if not NULL */ + short initial_state; /* initial state of toggleButton/toggleButtonGadget menu items */ +} MenuItem; + +#endif /* INCaxAreah */ + diff --git a/axRunW.c b/axRunW.c new file mode 100644 index 0000000..f45c9af --- /dev/null +++ b/axRunW.c @@ -0,0 +1,534 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* axRunW.c */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alh.h" +#include "axArea.h" +#include "ax.h" + +/************************DESCRIPTION*********************************** + This file contains all the routines related to the iconlike runtime window + and silence buttons. Functions include display, unmapping, remapping of main + window, alarm beeping, and blinking of control button. +**********************************************************************/ + +#define BLINK_DELAY 1000 /* ms */ +static XtIntervalId blinkTimeoutId = (XtIntervalId)0; +static char *bg_color[] = {"lightblue","yellow","red","white","white","grey"}; + +static char *channel_bg_color = "lightblue"; +static char *silenced_bg_color = "lightpink"; + + +/* global variabless */ +Widget blinkToplevel; /* Albert1 for locking status marking*/ +extern Display *display; +extern struct setup psetup; +extern char *programName; +extern Pixmap ALH_pixmap; +Pixel bg_pixel[ALH_ALARM_NSEV]; +Pixel channel_bg_pixel; +Pixel silenced_bg_pixel; +const char *bg_char[] = {" ", "Y", "R", "V", "E"," " }; + +/* forward declarations */ +static void axExit_callback(Widget w,ALINK *area,XmAnyCallbackStruct *call_data); +static void axExitArea_callback(Widget w,ALINK *area,XmAnyCallbackStruct *call_data); +static void blinking(XtPointer pointer, XtIntervalId *id); +static void createMainWindow_callback(Widget w,ALINK *area,XmAnyCallbackStruct *call_data); +static void icon_update(Widget blinkButton); +static void silenceOneHourReset(void *area); +static void changeTreeColor(Widget widget,Pixel color); +char *Strncat( + char *dest, + const char *src, + int max ); + +static void topWinEventHandler ( + Widget w, + XtPointer client, + XEvent *e, + Boolean *continueToDispatch ) { + +XConfigureEvent *ce; +ALINK *area; + + area = (ALINK *) client; + + *continueToDispatch = True; + + if ( e->type == ConfigureNotify ) { + + ce = (XConfigureEvent *) e; + + /*printf( "ce->width = %-d\n", ce->width);*/ + /*printf( "ce->height = %-d\n", ce->height);*/ + + area->w = ce->width; + area->h = ce->height; + + } + +} + +/****************************************************** + createRuntimeWindow +******************************************************/ +void createRuntimeWindow(ALINK *area) +{ + + char buff[LINEMESSAGE_SIZE], labelStr[80+1]; + MASK mask; + int i; + const char *alhTitle={"Alarm Handler"}; + XmString str; + XFontStruct *btnFont; + XmFontListEntry fontListEntry; + XmFontList fontList; + char *envPtr; + + if (!area->runtimeToplevel){ + /* create toplevel setup window */ + area->runtimeToplevel = XtAppCreateShell( "alh-run", programName, + applicationShellWidgetClass, display, NULL, 0); + + blinkToplevel = area->runtimeToplevel; /* Albert1 for locking status marking*/ + + XtVaSetValues(area->runtimeToplevel, XmNtitle, alhTitle, NULL); + + /* create bulletin board widget */ + area->runtimeForm = XtVaCreateManagedWidget("bulletinBoard1", + xmFormWidgetClass, area->runtimeToplevel, + XmNborderWidth, (Dimension)1, + XmNmarginWidth, (short)5, + XmNmarginHeight, (short)5, + XmNresizePolicy, XmRESIZE_NONE, + (XtPointer)NULL); + + if (!ALH_pixmap) axMakePixmap(area->runtimeForm); + + XtVaSetValues(area->runtimeToplevel, +#ifndef WIN32 + XmNiconPixmap, ALH_pixmap, +#endif + XmNiconName, area->blinkString, + XmNallowShellResize, TRUE, + XmNuserData, (XtPointer)area, + (XtPointer)NULL); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(area->runtimeToplevel, + XmNdeleteResponse, XmDO_NOTHING, + NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(area->runtimeToplevel), + "WM_DELETE_WINDOW", False); + if (programId == ALH) + XmAddWMProtocolCallback(area->runtimeToplevel,WM_DELETE_WINDOW, + (XtCallbackProc) axExit_callback, (XtPointer)area ); + else XmAddWMProtocolCallback(area->runtimeToplevel,WM_DELETE_WINDOW, + (XtCallbackProc) axExitArea_callback, (XtPointer)area ); + } + + envPtr = getenv( "ALHMAINFONT" ); + if ( envPtr ) { + btnFont = XLoadQueryFont(display,envPtr); + fontListEntry = XmFontListEntryCreate( "btnfont", XmFONT_IS_FONT, btnFont ); + fontList = XmFontListAppendEntry( NULL, fontListEntry ); + } + else { + fontList = NULL; + } + + /* create control button */ + str = XmStringCreateLtoR( "--- No config file specified. ---", + XmSTRING_DEFAULT_CHARSET); + area->blinkButton = XtVaCreateManagedWidget("iconButton", + xmPushButtonWidgetClass, area->runtimeForm, + XmNalignment, XmALIGNMENT_CENTER, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNactivateCallback, (XtPointer)NULL, + XmNuserData, (XtPointer)area, + XmNlabelString, str, + XmNfontList, fontList, + (XtPointer)NULL); + XmStringFree(str); + + XtAddCallback(area->blinkButton,XmNactivateCallback, + (XtCallbackProc)createMainWindow_callback, area); + + XtRealizeWidget(area->runtimeToplevel); + + XtAddEventHandler( area->runtimeToplevel, StructureNotifyMask, False, + topWinEventHandler, (XtPointer) area ); + + + } else { + XMapWindow(XtDisplay(area->runtimeToplevel), + XtWindow(area->runtimeToplevel)); + } + + pixelData(area->runtimeForm); + + /* update blinkButton string */ + str = XmStringCreateSimple(area->blinkString); + XtVaSetValues(area->blinkButton, + XmNlabelString, str, + NULL); + XmStringFree(str); + + /* reinitialize silence beep */ + silenceCurrentReset(area); + silenceOneHourReset(area); + + icon_update(area->blinkButton); + + mask.Unused = mask.Cancel = mask.Disable = mask.Ack = mask.AckT = mask.Log = 0; + for ( i=0; ipmainGroup->p1stgroup->pgroupData->mask[i] > 0 ); + } + else if ( i == ALARMDISABLE ) { + mask.Disable = ( area->pmainGroup->p1stgroup->pgroupData->mask[i] > 0 ); + } + else if ( i == ALARMACK ) { + mask.Ack = ( area->pmainGroup->p1stgroup->pgroupData->mask[i] > 0 ); + } + else if ( i == ALARMACKT ) { + mask.AckT = ( area->pmainGroup->p1stgroup->pgroupData->mask[i] > 0 ); + } + else if ( i == ALARMLOG ) { + mask.Log = ( area->pmainGroup->p1stgroup->pgroupData->mask[i] > 0 ); + } + } + + alGetMaskString(mask,buff); + + strncpy( labelStr, area->blinkString, 80 ); + labelStr[80] = 0; + + if ( strcmp( buff, "-----" ) != 0 ) { + + Strncat( labelStr, " <", 80 ); + labelStr[80] = 0; + + Strncat( labelStr, buff, 80 ); + labelStr[80] = 0; + + Strncat( labelStr, ">", 80 ); + labelStr[80] = 0; + + } + + str = XmStringCreateSimple(labelStr); + XtVaSetValues(area->blinkButton, + XmNlabelString, str, + NULL); + XmStringFree(str); + +} + +/****************************************************** + axExit_callback +******************************************************/ +static void axExit_callback(Widget w,ALINK *area, + XmAnyCallbackStruct *call_data) +{ + createActionDialog(area->runtimeToplevel,XmDIALOG_WARNING, + "Exit Alarm Handler?",(XtCallbackProc)exit_quit, + (XtPointer)area, (XtPointer)area); +} + +/****************************************************** + axExitArea_callback +******************************************************/ +static void axExitArea_callback(Widget w,ALINK *area, + XmAnyCallbackStruct *call_data) +{ + SNODE *proot; + + alLogOpModMessage(0,0,"Setup---Exit"); + XUnmapWindow(XtDisplay(area->runtimeToplevel), + XtWindow(area->runtimeToplevel)); + if (area->toplevel) { + XUnmapWindow(XtDisplay(area->toplevel),XtWindow(area->toplevel)); + } + area->mapped = FALSE; + area->managed = FALSE; + if (area->programId == ALH) alCaCancel(area->pmainGroup); + + /* Delete the current config */ + if (area->pmainGroup){ + proot = sllFirst(area->pmainGroup); + if (proot) alDeleteGroup((GLINK *)proot); + } + alHeartbeatPVRemove(area->pmainGroup); + free(area->pmainGroup); + area->pmainGroup = NULL; +} + +/****************************************************** + createMainWindow_callback +******************************************************/ +static void createMainWindow_callback(Widget w,ALINK *area, + XmAnyCallbackStruct *call_data) +{ + showMainWindow(area); +} + +/****************************************************** + Update runtime window +******************************************************/ +static void icon_update(Widget blinkButton) +{ + + XmChangeColor(blinkButton,bg_pixel[0]); + + /* Remove any existing timer */ + if (blinkTimeoutId) { + XtRemoveTimeOut(blinkTimeoutId); + blinkTimeoutId = 0; + } + + /* Restart the timer */ + blinkTimeoutId = XtAppAddTimeOut(appContext,BLINK_DELAY,blinking,(XtPointer)blinkButton); +} + +/****************************************************** + Initiate runtime window blinking +******************************************************/ +static void blinking(XtPointer pointer, XtIntervalId *id) +{ + Widget blinkButton = (Widget)pointer; + Display *displayBB; + static Pixel blinkPixel = 0; + static Boolean blinking2State = FALSE; + + if (!blinkPixel) blinkPixel = bg_pixel[0]; + displayBB = XtDisplay(blinkButton); + + if (!blinking2State) { + + if (psetup.highestSevr > 0 || + psetup.highestUnackSevr > 0 || + blinkPixel != bg_pixel[0]) { + + if (psetup.highestUnackSevr > 0) + blinkPixel = bg_pixel[psetup.highestUnackSevr]; + else + blinkPixel = bg_pixel[psetup.highestSevr]; + + XmChangeColor(blinkButton,blinkPixel); + } + if (!psetup.silenceForever && + !psetup.silenceOneHour && + !psetup.silenceCurrent && + (psetup.highestUnackBeepSevr >= psetup.beepSevr)) { + + alBeep(displayBB); + + XRaiseWindow(displayBB,XtWindow(XtParent(XtParent(blinkButton)))); + } + blinkTimeoutId = XtAppAddTimeOut(appContext,BLINK_DELAY, + blinking,blinkButton); + blinking2State = TRUE; + + } else { + if (psetup.highestUnackSevr > 0) { + XmChangeColor(blinkButton,bg_pixel[0]); + } + blinkTimeoutId = XtAppAddTimeOut(appContext,BLINK_DELAY, + blinking,blinkButton); + blinking2State = FALSE; + } + XFlush(displayBB); +} + +/*********************************************** + Reset silenceCurrentReset (to on state) +************************************************/ +void silenceCurrentReset(void *area) +{ + if (psetup.silenceCurrent) { + psetup.silenceCurrent = FALSE; + if (((ALINK*)area)->silenceCurrent) { + XmToggleButtonGadgetSetState(((ALINK*)area)->silenceCurrent, + FALSE,FALSE); + } + } +} + +/*********************************************** + reset silenceOneHourReset +************************************************/ +static void silenceOneHourReset(void *area) +{ + if (psetup.silenceOneHour) { + XmToggleButtonGadgetSetState(((ALINK*)area)->silenceOneHour,FALSE,FALSE); + silenceOneHour_callback(((ALINK*)area)->silenceOneHour,area,NULL); + } +} + +/*************************************************** + silenceCurrent button toggle callback +****************************************************/ +void silenceCurrent_callback(Widget w,ALINK *area, +XmAnyCallbackStruct *call_data) +{ + psetup.silenceCurrent = psetup.silenceCurrent?FALSE:TRUE; + if (psetup.silenceCurrent) + alLogOpModMessage(0,0,"Silence Current set to TRUE"); + else + alLogOpModMessage(0,0,"Silence Current set to FALSE"); +} + +/*************************************************** + silenceOneHour button toggle callback +****************************************************/ +void silenceOneHour_callback(Widget w,ALINK* area, +XmAnyCallbackStruct *call_data) +{ + static XtIntervalId intervalId = 0; + int seconds = 3600; + + psetup.silenceOneHour = psetup.silenceOneHour?FALSE:TRUE; + if (psetup.silenceOneHour) { + intervalId = XtAppAddTimeOut(appContext, + (unsigned long)(1000*seconds), + (XtTimerCallbackProc)silenceOneHourReset, + (XtPointer)area); + XmChangeColor(area->messageArea,silenced_bg_pixel); + changeTreeColor(area->treeWindowForm,silenced_bg_pixel); + changeTreeColor(area->groupWindowForm,silenced_bg_pixel); + changeTreeColor(area->scale,silenced_bg_pixel); + alLogOpModMessage(0,0,"Silence One Hour set to TRUE"); + } else { + if (intervalId) { + XtRemoveTimeOut(intervalId); + intervalId = 0; + } + XmChangeColor(area->messageArea,bg_pixel[0]); + changeTreeColor(area->treeWindowForm,bg_pixel[0]); + changeTreeColor(area->groupWindowForm,bg_pixel[0]); + changeTreeColor(area->scale,bg_pixel[0]); + alLogOpModMessage(0,0,"Silence One Hour set to FALSE"); + } +} + +/*************************************************** + changeTreeColor +****************************************************/ +static void changeTreeColor(Widget widget,Pixel color) +{ + int i; + Widget *children; + Cardinal numChildren = 0; + char *name; + + if (!widget || !color) return; + XtVaGetValues(widget,XmNnumChildren,&numChildren, NULL); + if (numChildren > 0) { + XtVaGetValues(widget,XmNchildren,&children, NULL); + for(i=0; i < (int)numChildren; i++) { + changeTreeColor(children[i],color); + } + } + name = XtName(widget); + if( !name || + ( strcmp(name,"ack") && + strcmp(name,"sevr") && + strcmp(name,"pushButtonName")) ) { + XmChangeColor(widget,color); + } +} + + +/*************************************************** + silenceForeverChangeState +****************************************************/ +void silenceForeverChangeState(ALINK *area) +{ + psetup.silenceForever = psetup.silenceForever?FALSE:TRUE; + if (psetup.silenceForever) + alLogOpModMessage(0,0,"Silence Forever set to TRUE"); + else + alLogOpModMessage(0,0,"Silence Forever set to FALSE"); + changeSilenceForeverText(area); +} + +/******************************************************** + trapExtraneousWarningsHandler +*******************************************************/ +XtErrorMsgHandler trapExtraneousWarningsHandler(String message) +{ + if (message && *message) { + if (!strcmp(message,"Attempt to remove non-existant passive grab")) + return 0; + else + (void)fprintf(stderr,"Warning: %s\n",message); + } + return 0; +} + +/****************************************************** + COLOR +******************************************************/ +static unsigned long COLOR(Display *dsply,char *name) +{ + XColor color; + Colormap cmap; + + cmap = DefaultColormap(dsply,DefaultScreen(dsply)); + color.pixel = 0; + XParseColor(dsply, cmap, name, &color); + XAllocColor(dsply, cmap, &color); + return(color.pixel); +} + +/***************************************************** + Setup pixel and font data +*****************************************************/ +void pixelData(Widget iconBoard) +{ + Display *dsply; + int n; + + /* get bg color pixel */ + dsply = XtDisplay(iconBoard); + for (n=1;n +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alh.h" +#include "sllLib.h" +#include "line.h" +#include "axSubW.h" +#include "axArea.h" +#include "ax.h" + +/* globals */ +extern Pixel bg_pixel[ALH_ALARM_NSEV]; + +/*************************************************** + scrollBarMovedCallback +****************************************************/ +static void scrollBarMovedCallback(Widget widget,struct subWindow *subWindow, +XmScrollBarCallbackStruct *cbs) +{ + if ((int)subWindow->viewOffset == cbs->value) return; + subWindow->viewOffset = cbs->value; + redraw(subWindow,0); +} + +/*************************************************** + setParentLink +****************************************************/ +void setParentLink(struct subWindow *subWindow,void *link) +{ + subWindow->parentLink = link; +} + +/*************************************************** + setLineRoutine +****************************************************/ +void setLineRoutine(void *area,struct subWindow *subWindow,int program) +{ + /* Set line widget creation/modify routines to default values */ + if (isTreeWindow(area,subWindow)) { + subWindow->alViewNth = ( void *(*)())alViewNthTreeW; + subWindow->alViewNext = ( void *(*)())alViewNextTreeW; + subWindow->alViewMaxSevrN = alViewMaxSevrNTreeW; + } else { + subWindow->alViewNth = (void *(*)())alViewNthGroupW; + subWindow->alViewNext = (void *(*)())alViewNextGroupW; + subWindow->alViewMaxSevrN = alViewMaxSevrNGroupW; + } +} +/*************************************************** + markSelectedWidget +****************************************************/ +void markSelectedWidget(struct subWindow *subWindow,Widget newWidget) +{ + static Pixel armColor=0; + static Pixel backgroundColor=0; + static Pixel bottomShadowColor=0; + static Pixel topShadowColor=0; + Widget oldWidget; + + oldWidget = subWindow->selectionWidget; + if (oldWidget == newWidget ) return; + + if (oldWidget) { + XtVaGetValues(oldWidget, + XmNbackground, &backgroundColor, + XmNarmColor, &armColor, + XmNtopShadowColor, &topShadowColor, + XmNbottomShadowColor,&bottomShadowColor, + (XtPointer)NULL); + + XtVaSetValues(oldWidget, + XmNbackground, armColor, + XmNarmColor, backgroundColor, + XmNtopShadowColor, bottomShadowColor, + XmNbottomShadowColor,topShadowColor, + NULL); + } + + if (newWidget) { + XtVaGetValues(newWidget, + XmNbackground, &backgroundColor, + XmNarmColor, &armColor, + XmNtopShadowColor, &topShadowColor, + XmNbottomShadowColor,&bottomShadowColor, + (XtPointer)NULL); + + XtVaSetValues(newWidget, + XmNbackground, armColor, + XmNarmColor, backgroundColor, + XmNtopShadowColor, bottomShadowColor, + XmNbottomShadowColor,topShadowColor, + NULL); + } + subWindow->selectionWidget = newWidget; + markActiveWidget(subWindow->area,newWidget); +} + +/*************************************************** + initializeSubWindow +****************************************************/ +void initializeSubWindow(struct subWindow *subWindow) +{ + subWindow->modified = FALSE; + subWindow->viewOffset = 0; + + /* Make NULL the selected group */ + subWindow->selectionLink = NULL; + subWindow->parentLink = NULL; + + subWindow->viewConfigCount = 0; + subWindow->oldViewConfigCount = 0; + + initializeLines((SNODE *)subWindow->lines); +} + +/*************************************************** + setViewConfigCount +****************************************************/ +void setViewConfigCount(struct subWindow *subWindow,int count) +{ + subWindow->viewConfigCount = count; + /* + subWindow->oldViewConfigCount = 0; + */ +} + +/*************************************************** + invokeSubWindowUpdate +****************************************************/ +void invokeSubWindowUpdate(struct subWindow *subWindow) +{ + SLIST *lines; + struct anyLine *line; + void *link=0; + int linkType; + + if (subWindow->modified){ + redraw(subWindow,0); + subWindow->modified = 0; + return; + } + + lines = subWindow->lines; + if (!lines) return; + + /* update modified lines */ + line = (struct anyLine *)sllFirst(lines); + while (line){ + invokeLinkUpdate((GCLINK *)line->link,line->linkType); + if (line->link ){ + link = line->link; + linkType = line->linkType; + } + line = (struct anyLine *)sllNext(line); + } + + /* update the severity below indicator */ + if (link) { + link = (subWindow->alViewNext)(link,&linkType); + if (link) initSevrBelow(subWindow,link); + } + + /* update the severity above indicator */ + link = (subWindow->alViewNth)(subWindow->parentLink,&linkType,0); + initSevrAbove(subWindow,link); +} + +/*************************************************** + createSubWindow +****************************************************/ +struct subWindow *createSubWindow(void *area) +{ + struct subWindow *subWindow; + + subWindow =(struct subWindow *)calloc(1,sizeof(struct subWindow)); + + subWindow->area = (void *)area; + + /* allocate and initialize a list for line data */ + subWindow->lines = (SLIST *)calloc(1,sizeof(SLIST)); + sllInit(subWindow->lines); + + return(subWindow); +} + +/*************************************************** + createSubWindowWidgets +****************************************************/ +void createSubWindowWidgets(struct subWindow *subWindow,Widget parent) +{ + Pixel color=0; + Dimension width=0; + + /* Create a Form for sevr indicators and scrollbar */ + subWindow->form_vsb = XtVaCreateWidget("form_vsb", + xmFormWidgetClass, parent, + XmNorientation, XmVERTICAL, + XmNadjustLast, TRUE, + XmNtopAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + NULL); + + subWindow->sevrAboveInd = XtVaCreateManagedWidget("sevrAboveInd", + xmLabelWidgetClass, subWindow->form_vsb, + XmNlabelType, XmPIXMAP, + XmNborderWidth, 1, + XmNtopAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + NULL); + + subWindow->sevrBelowInd = XtVaCreateManagedWidget(" ", + xmLabelWidgetClass, subWindow->form_vsb, + XmNlabelType, XmPIXMAP, + XmNborderWidth, 1, + XmNrightAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + NULL); + + /* Create vertical scrollbar for the tree area */ + subWindow->vsb = XtVaCreateManagedWidget("vsb", + xmScrollBarWidgetClass, subWindow->form_vsb, + XmNorientation, XmVERTICAL, + XmNrepeatDelay, 200, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, subWindow->sevrAboveInd, + XmNbottomAttachment, XmATTACH_WIDGET, + XmNbottomWidget, subWindow->sevrBelowInd, + XmNrightAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + NULL); + + + /* manage the Form for sevr indicators and scrollbar in the sub */ + XtManageChild(subWindow->form_vsb); + + /* use same callback for all callback reasons */ + XtAddCallback(subWindow->vsb, + XmNvalueChangedCallback, + (XtCallbackProc)scrollBarMovedCallback, subWindow); + XtAddCallback(subWindow->vsb, + XmNdragCallback, + (XtCallbackProc)scrollBarMovedCallback, subWindow); + + XtVaGetValues(subWindow->vsb, + XmNwidth, &width, + XmNtroughColor, &color, + NULL); + + XtVaSetValues(subWindow->sevrAboveInd, + XmNbackground, color, + XmNheight, width, + XmNwidth, width, + NULL); + XtVaSetValues(subWindow->sevrBelowInd, + XmNbackground, color, + XmNheight, width, + XmNwidth, width, + NULL); + + /* Create DrawingArea to hold the line widgets */ + subWindow->drawing_area = XtVaCreateManagedWidget("drawing_area", + xmDrawingAreaWidgetClass, parent, + XmNresizePolicy, XmRESIZE_NONE, + XmNmarginHeight, 3, + XmNspacing, 0, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + NULL); +} + +/*************************************************** + calcRowCount +****************************************************/ +int calcRowCount(struct subWindow *subWindow) +{ + int viewRowCount; + viewRowCount =(int)((int)(subWindow->viewHeight-2*subWindow->marginHeight)/ + (int)(2+subWindow->rowHeight)); + return(viewRowCount); +} + +/*************************************************** + calcRowYValue +****************************************************/ +int calcRowYValue(struct subWindow *subWindow,int lineNo) +{ + int yValue; + yValue = (int)(2+subWindow->rowHeight)*lineNo + subWindow->marginHeight; + + return(yValue); +} + +/*************************************************** + adjustScrollBar +****************************************************/ +void adjustScrollBar(struct subWindow *subWindow) +{ + /* adjust scrollbar and slider if viewRowCount or viewConfigCount changed*/ + if ( !subWindow->viewRowCount || !subWindow->viewConfigCount) + XtUnmanageChild(subWindow->form_vsb); + + if ( subWindow->viewRowCount != subWindow->oldViewRowCount || + subWindow->viewConfigCount != subWindow->oldViewConfigCount ){ + + if ( XtIsManaged(subWindow->form_vsb) == TRUE ) + XtUnmanageChild(subWindow->form_vsb); + + /* set slider values */ + XtVaSetValues(subWindow->vsb, + XmNvalue, subWindow->viewOffset, + XmNmaximum, Mmax(subWindow->viewRowCount, + subWindow->viewConfigCount), + XmNsliderSize, Mmax(subWindow->viewRowCount, 1), + XmNpageIncrement, Mmax(subWindow->viewRowCount-1, 1), + (XtPointer)NULL); + + /* manage/unmanage scrollbar */ + if ( subWindow->viewConfigCount <= subWindow->viewRowCount ){ + if ( XtIsManaged(subWindow->form_vsb) == TRUE ){ + XtUnmanageChild(subWindow->form_vsb); + } + } else { + if ( XtIsManaged(subWindow->form_vsb) == FALSE ){ + XtManageChild(subWindow->form_vsb); + } + } + + subWindow->oldViewConfigCount = subWindow->viewConfigCount; + subWindow->oldViewRowCount = subWindow->viewRowCount; + } +} + +/*************************************************** + exposeResizeCallback +****************************************************/ +void exposeResizeCallback(Widget widget,struct subWindow *subWindow, +XEvent *cbs) +{ + Dimension oldViewHeight; + + /* + if (cbs->reason == XmCR_EXPOSE){ + return; + } + */ + oldViewHeight = subWindow->viewHeight; + XtVaGetValues(subWindow->drawing_area, + XmNheight, &subWindow->viewHeight, + XmNmarginHeight, &subWindow->marginHeight, + NULL); + + subWindow->oldViewRowCount = subWindow->viewRowCount; + if ( subWindow->rowHeight ){ + subWindow->viewRowCount = calcRowCount(subWindow); + } + + if (subWindow->viewRowCount <= 0) return; + + redraw(subWindow,0); + + /* because redraw is slow we get into trouble with following stmnts + with many frequent calls to resize + */ +#if 0 + if (subWindow->viewHeight == oldViewHeight) return; + + if (subWindow->viewHeight < oldViewHeight) { + if (subWindow->viewRowCount < subWindow->viewConfigCount){ + redraw(subWindow,subWindow->viewRowCount); + } else return; + } else{ + redraw(subWindow,subWindow->oldViewRowCount); + } +#endif +} + +/*************************************************** + defaultTreeSelection +****************************************************/ +void defaultTreeSelection(ALINK *area) +{ + struct subWindow *treeWindow; + struct subWindow *groupWindow; + struct anyLine *line; + WLINE *wline; + + treeWindow = (struct subWindow *)area->treeWindow; + groupWindow = (struct subWindow *)area->groupWindow; + if (!treeWindow->lines) return; + line = (struct anyLine *)sllFirst(treeWindow->lines); + if (!line) return; + wline = (WLINE *)(line->wline); + + markSelectedWidget(treeWindow,wline->name); + markSelection(treeWindow, line); + + /* groupWindow must now display contents of new treeWindow selection */ + groupWindow->parentLink = line->link; + groupWindow->viewConfigCount = + alViewAdjustGroupW((GLINK *)line->link,area->viewFilter); + groupWindow->viewOffset = 0; + redraw(groupWindow,0); +} + +/*************************************************** + initSevrAbove +****************************************************/ +void initSevrAbove(struct subWindow *subWindow,void *link) +{ + int sevrAbove; + + if ( XtIsManaged(subWindow->form_vsb) == TRUE ){ + + sevrAbove = (subWindow->alViewMaxSevrN)(link,subWindow->viewOffset); +#if XmVersion && XmVersion >= 1002 + XmChangeColor(subWindow->sevrAboveInd,bg_pixel[sevrAbove]); +#else + XtVaSetValues(subWindow->sevrAboveInd,XmNbackground, + bg_pixel[sevrAbove],NULL); +#endif + } +} + +/*************************************************** + initSevrBelow +****************************************************/ +void initSevrBelow(struct subWindow *subWindow,void *link) +{ + int sevrBelow,n; + + if ( XtIsManaged(subWindow->form_vsb) == TRUE ){ + + n = subWindow->viewConfigCount - subWindow->viewOffset - subWindow->viewRowCount; + + sevrBelow = (subWindow->alViewMaxSevrN)(link,n); + if (sevrBelow < 0 ) return; +#if XmVersion && XmVersion >= 1002 + XmChangeColor(subWindow->sevrBelowInd,bg_pixel[sevrBelow]); +#else + XtVaSetValues(subWindow->sevrBelowInd,XmNbackground,bg_pixel[sevrBelow],NULL); +#endif + } +} + diff --git a/axSubW.h b/axSubW.h new file mode 100644 index 0000000..10e14de --- /dev/null +++ b/axSubW.h @@ -0,0 +1,61 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* axSubW.h */ + +/************************DESCRIPTION*********************************** + structure for subWindows +**********************************************************************/ + +#ifndef INCaxSubWh +#define INCaxSubWh + +#include + +#include "sllLib.h" + +/* display sub window structure */ +struct subWindow { + /* ----- Window info ----- */ + void *area; + Widget drawing_area; + Widget scrolled_w; + Widget form_vsb; + Widget sevrAboveInd; + Widget vsb; + Widget sevrBelowInd; + Dimension viewHeight; + Dimension rowHeight; + Dimension marginHeight; + int viewRowCount; + int oldViewRowCount; + /* ----- Config info ----- */ + int modified; + void *parentLink; + int viewConfigCount; + int oldViewConfigCount; + unsigned int viewOffset; + /* ----- view routines ----- */ + void *(*alViewNth)(); + void *(*alViewNext)(); + int (*alViewMaxSevrN)(); + /* ----- Selection info ----- */ + void *selectionLink; + Widget selectionWidget; + /* ----- line item info ----- */ + SLIST *lines; +}; + +#endif + diff --git a/beepSevr.c b/beepSevr.c new file mode 100644 index 0000000..c30409e --- /dev/null +++ b/beepSevr.c @@ -0,0 +1,380 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* beepSevr.c */ + +/************************DESCRIPTION*********************************** + beepSevr.c: a popup dialog window + This file contains routines for creating beep severity dialog. +**********************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "axArea.h" +#include "alLib.h" +#include "alh.h" +#include "ax.h" +#include "alarm.h" + +struct beepSevrWindow { + void *area; + Widget menuButton; + Widget beepSevrDialog; + Widget nameLabelW; + Widget nameTextW; + Widget beepSevrFrameW; + Widget beepSevrToggleButtonW[ALH_ALARM_NSEV-1]; + int beepSevr; +}; + +extern const char * alhAlarmSeverityString[]; + +/* forward declarations */ +static void beepSevrDismissCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void beepSevrHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void beepSevrCreateDialog(ALINK*area); +static void beepSevrUpdateDialogWidgets(struct beepSevrWindow *beepSevrWindow); +static void beepSevrChangeCallback( Widget widget,XtPointer calldata,XtPointer cbs); + + +/****************************************************** + beepSevrUpdateDialog +******************************************************/ +void beepSevrUpdateDialog(area) +ALINK *area; +{ + struct beepSevrWindow *beepSevrWindow; + + if (!area->beepSevrWindow) return; + + beepSevrWindow = (struct beepSevrWindow *)area->beepSevrWindow; + + if (!beepSevrWindow->beepSevrDialog || !XtIsManaged(beepSevrWindow->beepSevrDialog)) return; + + beepSevrUpdateDialogWidgets(beepSevrWindow); +} + +/****************************************************** + beepSevrShowDialog +******************************************************/ +void beepSevrShowDialog(area, menuButton) +ALINK *area; +Widget menuButton; +{ + struct beepSevrWindow *beepSevrWindow; + + beepSevrWindow = (struct beepSevrWindow *)area->beepSevrWindow; + + /* Dismiss Dialog */ + if (beepSevrWindow && beepSevrWindow->beepSevrDialog && + XtIsManaged(beepSevrWindow->beepSevrDialog)) { + beepSevrDismissCallback(NULL, (XtPointer)beepSevrWindow, NULL); + return; + } + + /* create beepSevrWindow and Dialog Widgets if necessary */ + if (!beepSevrWindow) beepSevrCreateDialog(area); + + /* update beepSevrWindow */ + beepSevrWindow = (struct beepSevrWindow *)area->beepSevrWindow; + beepSevrWindow->menuButton = menuButton; + + /* update Dialog Widgets */ + beepSevrUpdateDialogWidgets(beepSevrWindow); + + /* show Dialog */ + if (!beepSevrWindow->beepSevrDialog) return; + if (!XtIsManaged(beepSevrWindow->beepSevrDialog)) { + XtManageChild(beepSevrWindow->beepSevrDialog); + } + XMapWindow(XtDisplay(beepSevrWindow->beepSevrDialog), + XtWindow(XtParent(beepSevrWindow->beepSevrDialog))); + if (menuButton) XtVaSetValues(menuButton, XmNset, TRUE, NULL); + +} + +/****************************************************** + beepSevrUpdateDialogWidgets +******************************************************/ + +static void beepSevrUpdateDialogWidgets(beepSevrWindow) +struct beepSevrWindow *beepSevrWindow; +{ + struct gcData *pgcData; + GCLINK *link; + int i,linkType; + int beepSevr; + XmString string; + + if (! beepSevrWindow || !beepSevrWindow->beepSevrDialog ) return; + + link = (GCLINK *)getSelectionLinkArea(beepSevrWindow->area); + + if (!link) { + + string = XmStringCreateSimple(""); + XtVaSetValues(beepSevrWindow->nameTextW,XmNlabelString, string, NULL); + XmStringFree(string); + return; + } + + linkType = getSelectionLinkTypeArea(beepSevrWindow->area); + + pgcData = link->pgcData; + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + if (linkType == GROUP) string = XmStringCreateSimple("Group Name:"); + else string = XmStringCreateSimple("Channel Name:"); + XtVaSetValues(beepSevrWindow->nameLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + + if (pgcData->alias){ + string = XmStringCreateSimple(pgcData->alias); + } else { + string = XmStringCreateSimple(pgcData->name); + } + XtVaSetValues(beepSevrWindow->nameTextW, XmNlabelString, string, NULL); + XmStringFree(string); + + /* --------------------------------- + Beep Severity + --------------------------------- */ + beepSevr = pgcData->beepSevr; + if (beepSevr == 0) beepSevr=1; + for (i = 0; i < ALH_ALARM_NSEV-1; i++){ + XmToggleButtonGadgetSetState(beepSevrWindow->beepSevrToggleButtonW[i], False, False); + } + XmToggleButtonGadgetSetState(beepSevrWindow->beepSevrToggleButtonW[beepSevr-1], True, False); + +} + +/****************************************************** + beepSevrCreateDialog +******************************************************/ +static void beepSevrCreateDialog(area) +ALINK *area; +{ + struct beepSevrWindow *beepSevrWindow; + + Widget beepSevrDialogShell, beepSevrDialog; + Widget radiobox, form, beepSevrFrameW; + Widget nameLabelW, nameTextW; + Widget beepSevrToggleButtonW[ALH_ALARM_NSEV-1]; + int i; + static ActionAreaItem beepSevr_items[] = { + { "Dismiss", beepSevrDismissCallback, NULL }, + { "Help", beepSevrHelpCallback, NULL }, + }; + + if (!area) return; + + beepSevrWindow = (struct beepSevrWindow *)area->beepSevrWindow; + + if (beepSevrWindow && beepSevrWindow->beepSevrDialog){ + if (XtIsManaged(beepSevrWindow->beepSevrDialog)) return; + else XtManageChild(beepSevrWindow->beepSevrDialog); + } + + + beepSevrWindow = (struct beepSevrWindow *)calloc(1,sizeof(struct beepSevrWindow)); + area->beepSevrWindow = (void *)beepSevrWindow; + beepSevrWindow->area = (void *)area; + + beepSevrDialogShell = XtVaCreatePopupShell("Set Beep Severity", + transientShellWidgetClass, area->toplevel, + XmNallowShellResize, TRUE, + NULL); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(beepSevrDialogShell, + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(beepSevrDialogShell), + "WM_DELETE_WINDOW", False); + XmAddWMProtocolCallback(beepSevrDialogShell,WM_DELETE_WINDOW, + (XtCallbackProc)beepSevrDismissCallback, (XtPointer)beepSevrWindow); + } + + beepSevrDialog = XtVaCreateWidget("beepSevrDialog", + xmPanedWindowWidgetClass, beepSevrDialogShell, + XmNallowResize, TRUE, + XmNsashWidth, 1, + XmNsashHeight, 1, + XmNuserData, area, + NULL); + + + form = XtVaCreateWidget("control_area", + xmFormWidgetClass, beepSevrDialog, + XmNallowResize, TRUE, + NULL); + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + nameLabelW = XtVaCreateManagedWidget("nameLabelW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_END, + XmNtopAttachment, XmATTACH_FORM, +/* + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, +*/ + XmNrecomputeSize, True, + NULL); + + nameTextW = XtVaCreateManagedWidget("nameTextW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, nameLabelW, + XmNrightAttachment, XmATTACH_NONE, + XmNrecomputeSize, True, + NULL); + + /* --------------------------------- + Beep Severity + --------------------------------- */ + + beepSevrFrameW = XtVaCreateManagedWidget("beepSevrFrameW", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, nameLabelW, + XmNtopOffset, 5, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 25, + NULL); + + radiobox = XmCreateRadioBox (beepSevrFrameW, "radiobox", NULL, 0); + + for (i = 0; i < ALH_ALARM_NSEV-1; i++){ + beepSevrToggleButtonW[i] = XmCreateToggleButtonGadget (radiobox, + (char *)alhAlarmSeverityString[i+1], NULL, 0); + XtVaSetValues(beepSevrToggleButtonW[i], XmNuserData, area, NULL); + long ii=i+1; + XtAddCallback(beepSevrToggleButtonW[i], XmNvalueChangedCallback, + beepSevrChangeCallback, (XtPointer)ii); + XtManageChild(beepSevrToggleButtonW[i]); + + } + + XtManageChild(radiobox); + + XtManageChild(form); + + /* Set the client data "Apply", "Dismiss", "OK", and "Help" button's callbacks. */ + beepSevr_items[0].data = (XtPointer)beepSevrWindow; + beepSevr_items[1].data = (XtPointer)beepSevrWindow; + + (void)createActionButtons(beepSevrDialog, beepSevr_items, XtNumber(beepSevr_items)); + + beepSevrWindow->beepSevrDialog = beepSevrDialog; + beepSevrWindow->nameLabelW = nameLabelW; + beepSevrWindow->nameTextW = nameTextW; + beepSevrWindow->beepSevrFrameW = beepSevrFrameW; + for (i = 0; i < ALH_ALARM_NSEV-1; i++){ + beepSevrWindow->beepSevrToggleButtonW[i] = beepSevrToggleButtonW[i]; + } + + XtManageChild(beepSevrDialog); + + XtRealizeWidget(beepSevrDialogShell); + +} + +/****************************************************** + beepSevrHelpCallback +******************************************************/ +static void beepSevrHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + char *message1 = + "Set the beep severity level for a group or channel.\n" + "\n" + "Beep severity is the minimum severity level required for beeping.\n" + "Beeping for this group or channel will not occur when the highest\n" + "unacknowledged severity is less than the specified beep severity.\n" + "\n" + "Press the Dismiss button to close the dialog window.\n" + "Press the Help button to get this help description window.\n" + " \n" + ; + char * message2 = " "; + + createDialog(widget,XmDIALOG_INFORMATION, message1,message2); + +} + +/****************************************************** + beepSevrChangeCallback +******************************************************/ +static void beepSevrChangeCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + int beepSevr=(long)calldata; + ALINK *area; + struct gcData *pgcData; + GCLINK *link; + int linkType; + + if (!XmToggleButtonGadgetGetState(widget)) return; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + link =getSelectionLinkArea(area); + if (!link) return; + linkType =getSelectionLinkTypeArea(area); + if (linkType == CHANNEL) alSetBeepSevrChan((CLINK *)link,beepSevr); + if (linkType == GROUP) alSetBeepSevrGroup((GLINK *)link,beepSevr); + + pgcData = link->pgcData; + alLogOpModMessage(0,link,"Beep Severity set to %s",alhAlarmSeverityString[pgcData->beepSevr]); + + link->pmainGroup->modified = 1; + + /* --------------------------------- + Update all dialog Windows + --------------------------------- */ + axUpdateDialogs(area); + +} + +/****************************************************** + beepSevrDismissCallback +******************************************************/ +static void beepSevrDismissCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + struct beepSevrWindow *beepSevrWindow=(struct beepSevrWindow *)calldata; + Widget beepSevrDialog; + + beepSevrDialog = beepSevrWindow->beepSevrDialog; + XtUnmanageChild(beepSevrDialog); + XUnmapWindow(XtDisplay(beepSevrDialog), XtWindow(XtParent(beepSevrDialog))); + if (beepSevrWindow->menuButton) + XtVaSetValues(beepSevrWindow->menuButton, XmNset, FALSE, NULL); + +} + + diff --git a/browser.c b/browser.c new file mode 100644 index 0000000..b5103cc --- /dev/null +++ b/browser.c @@ -0,0 +1,372 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* browser.c */ + +/************************DESCRIPTION*********************************** + Invokes Netscape browser + Original Author : Kenneth Evans, Jr. +**********************************************************************/ + +/* Note that there are separate WIN32 and UNIX versions */ + +#define DEBUG 0 + +#ifndef WIN32 +/*************************************************************************/ +/*************************************************************************/ +/* Netscape UNIX Version */ +/*************************************************************************/ +/*************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef NETSCAPEPATH +#define NETSCAPEPATH "netscape" +#endif + +/* Function prototypes */ + +extern int kill(pid_t, int); /* May not be defined for strict ANSI */ + +int callBrowser(char *url); +static Window checkNetscapeWindow(Window w); +static int execute(char *s); +static Window findNetscapeWindow(void); +static int ignoreXError(Display *display, XErrorEvent *xev); + +/* Global variables */ +extern Display *display; + +/**************************** callBrowser ********************************/ +int callBrowser(char *url) +/* Returns non-zero on success, 0 on failure */ +/* url is the URL that the browser is to display */ +/* or "quit" to terminate the browser */ +{ + int (*oldhandler)(Display *, XErrorEvent *); + static Window netscapew=(Window)0; + static pid_t pid=0; + int status; + char command[BUFSIZ]; + char *envstring; + + /* Handle quit */ + if(!strcmp(url,"quit")) { + if (pid) { + kill(pid,SIGTERM); + pid=0; + } + return 3; + } + /* Set handler to ignore possible BadWindow error */ + /* (Would prefer a routine that tells if the window is defined) */ + oldhandler=XSetErrorHandler(ignoreXError); + /* Check if the stored window value is valid */ + netscapew=checkNetscapeWindow(netscapew); + /* Reset error handler */ + XSetErrorHandler(oldhandler); + /* If stored window is not valid, look for a valid one */ + if(!netscapew) { + netscapew=findNetscapeWindow(); + /* If no window found, exec Netscape */ + if(!netscapew) { + envstring=getenv("NETSCAPEPATH"); + if(!envstring) { + sprintf(command,"%s -install '%s' &",NETSCAPEPATH,url); + } + else { + sprintf(command,"%s -install '%s' &",envstring,url); + } +#if DEBUG + printf("execute(before): cmd=%s\n",command); +#endif + status=execute(command); +#if DEBUG + printf("execute(after): cmd=%s status=%d\n",command,status); +#endif + return 1; + } + } + /* Netscape window is valid, send url via -remote */ + /* (Use -id for speed) */ + envstring=getenv("NETSCAPEPATH"); + if(!envstring) { + sprintf(command,"%s -id 0x%x -remote 'openURL(%s)' &", + NETSCAPEPATH,(unsigned int)netscapew,url); + } + else { + sprintf(command,"%s -id 0x%x -remote 'openURL(%s)' &", + envstring,(unsigned int)netscapew,url); + } +#if DEBUG + printf("execute(before): cmd=%s\n",command); +#endif + status=execute(command); +#if DEBUG + printf("execute(after): cmd=%s status=%d\n",command,status); +#endif + return 2; +} +/**************************** checkNetscapeWindow ************************/ +static Window checkNetscapeWindow(Window w) +/* Checks if this window is the Netscape window and returns the window + * if it is or 0 otherwise */ +{ + Window wfound=(Window)0; + static Atom typeatom,versionatom=(Atom)0; + unsigned long nitems,bytesafter; + int format,status; + unsigned char *version=NULL; + + /* If window is NULL, return it */ + if(!w) return w; + /* Get the atom for the version property (once) */ + if(!versionatom) versionatom=XInternAtom(display,"_MOZILLA_VERSION",False); + /* Get the version property for this window if it exists */ + status=XGetWindowProperty(display,w,versionatom,0, + (65536/sizeof(long)),False,AnyPropertyType, + &typeatom,&format,&nitems,&bytesafter,&version); + /* If the version property exists, it is the Netscape window */ + if(version && status == Success) wfound=w; +#if DEBUG + printf("XGetWindowProperty: status=%d version=%d w=%x wfound=%x\n", + status,version,w,wfound); +#endif + /* Free space and return */ + if(version) XFree((void *)version); + return wfound; +} +/**************************** execute ************************************/ +static int execute(char *s) +/* From O'Reilly, Vol. 1, p. 438 */ +{ + int status,pid,w; + register void (*istat)(),(*qstat)(); + + if((pid=fork()) == 0) { + signal(SIGINT,SIG_DFL); + signal(SIGQUIT,SIG_DFL); + signal(SIGHUP,SIG_DFL); + execl("/bin/sh","sh","-c",s,(char *)0); + _exit(127); + } + istat=signal(SIGINT,SIG_IGN); + qstat=signal(SIGQUIT,SIG_IGN); + while((w=wait(&status)) != pid && w != -1) ; + if(w == -1) status=-1; + signal(SIGINT,istat); + signal(SIGQUIT,qstat); + return(status); +} +/**************************** findNetscapeWindow *************************/ +static Window findNetscapeWindow(void) +{ + int screen=DefaultScreen(display); + Window rootwindow=RootWindow(display,screen); + Window *children,dummy,w,wfound=(Window)0; + unsigned int nchildren; + int i; + + /* Get the root window tree */ + if(!XQueryTree(display,rootwindow,&dummy,&dummy,&children,&nchildren)) + return (Window)0; + /* Look at the children from the top of the stacking order */ + for(i=nchildren-1; i >= 0; i--) { + w=XmuClientWindow(display,children[i]); + /* Check if this is the Netscape window */ +#if DEBUG + printf("Child %d ",i); +#endif + wfound=checkNetscapeWindow(w); + if(wfound) break; + } + if(children) XFree((void *)children); + return wfound; +} +/**************************** ignoreXError *******************************/ +static int ignoreXError(Display *display, XErrorEvent *xev) +{ +#if DEBUG + printf("In ignoreXError\n"); +#endif + return 0; +} + +#else /*ifndef WIN32 */ +/*************************************************************************/ +/*************************************************************************/ +/* WIN32 Version */ +/*************************************************************************/ +/*************************************************************************/ + +#include +#include +#include +#include +#include + +/* void medmPrintf(int priority, char *format, ...); */ + +int callBrowser(char *url); + +/**************************** callBrowser (WIN32) ************************/ +int callBrowser(char *url) +/* Returns non-zero on success, 0 on failure */ +/* Should use the default browser */ +/* Does nothing with "quit" */ +{ + static int first=1; + static char *ComSpec; + char command[BUFSIZ]; + int status; + + /* Handle quit */ + if(!strcmp(url,"quit")) { + /* For compatibility, but do nothing */ + return(3); + } + + /* Get ComSpec for the command shell (should be defined) */ + if (first) { + first=0; + ComSpec = getenv("ComSpec"); + } + if (!ComSpec) return(0); /* Abort with no message like the UNIX version*/ + /* Spawn the process that handles a url */ +#if 0 + /* Works, command window that goes away */ + sprintf(command,"start \"%s\"",url); + status = _spawnl(_P_WAIT, ComSpec, ComSpec, "/C", command, NULL); + + /* Works, command window that goes away */ + sprintf(command,"start \"%s\"",url); + status = _spawnl(_P_DETACH, ComSpec, ComSpec, "/C", command, NULL); + + /* Works, command window that goes away */ + sprintf(command,"\"%s\"",url); + status = _spawnl(_P_NOWAIT, "c:\\windows\\command\\start.exe", + "c:\\windows\\command\\start.exe", command, NULL); + + /* Works, command window that goes away */ + sprintf(command,"\"%s\"",url); + status = _spawnl(_P_WAIT, ComSpec, "start", command, NULL); + + /* Works, command window that goes away */ + sprintf(command,"start \"%s\"",url); + status = _spawnl(_P_NOWAIT, ComSpec, ComSpec, "/C", command, NULL); + + /* Doesn't work on 95 (No such file or directory), works on NT */ + sprintf(command,"start \"%s\"",url); + status = _spawnl(_P_NOWAIT, ComSpec, "/C", command, NULL); + + /* Works on 95, not NT, no command window + * No start.exe for NT */ + sprintf(command,"\"%s\"",url); + status = _spawnlp(_P_DETACH, "start", "start", command, NULL); + + /* Doesn't work on 95 */ + sprintf(command,"\"start %s\"",url); + status = _spawnl(_P_DETACH, ComSpec, ComSpec, "/C", command, NULL); +#else + /* This seems to work on 95 and NT, with a command box on 95 + * It may have trouble if the URL has spaces */ + sprintf(command,"start %s",url); + status = _spawnl(_P_DETACH, ComSpec, ComSpec, "/C", command, NULL); +#endif + if(status == -1) { + char *errstring=strerror(errno); + + printf("\ncallBrowser: Cannot start browser:\n" + "%s %s\n" + " %s\n",ComSpec,command,errstring); + /* perror("callBrowser:"); */ + return(0); + } + return(1); +} +#endif /* #ifndef WIN32 */ + +#if 0 +/*************************************************************************/ +/*************************************************************************/ +/* Mosaic Version */ +/*************************************************************************/ +/*************************************************************************/ + +#ifndef MOSAICPATH +/* #define MOSAICPATH "/usr/bin/X11/mosaic" */ +/* #define MOSAICPATH "/opt/local/bin/mosaic" */ +#define MOSAICPATH "mosaic" +#endif + +/**************************** callBrowser ********************************/ +int callBrowser(char *url) +/* Returns non-zero on success, 0 on failure */ +/* url is the URL that Mosaic is to display */ +/* or "quit" to terminate Mosaic */ +{ + static pid_t pid=0; + char filename[32]; + FILE *file; + char path[BUFSIZ]; + char *envstring; + + signal(SIGCHLD,SIG_IGN); + + /* Handle quit */ + if(!strcmp(url,"quit")) { + if (pid) { + sprintf(filename,"/tmp/Mosaic.%d",pid); + unlink(filename); + kill(pid,SIGTERM); + pid=0; + } + return 3; + } + /* If Mosaic is not up, exec it */ + if ((!pid) || kill(pid,0)) { + if (!(pid=fork())) { + envstring=getenv("MOSAICPATH"); + if(!envstring) { + sprintf(path,"%s",MOSAICPATH); + } + else { + sprintf(path,"%s",envstring); + } + execlp(path,path,url,(char *)0); + perror(path); + _exit(127); + } + return 1; + } + /* Mosaic is up, send message through file */ + sprintf(filename,"/tmp/Mosaic.%d",pid); + if (!(file=fopen(filename,"w"))) return 0; + fprintf(file,"goto\n%s\n",url); + fclose(file); + kill(pid,SIGUSR1); + return 2; +} +#endif diff --git a/cmlogrc.ALH b/cmlogrc.ALH new file mode 100644 index 0000000..0e699f7 --- /dev/null +++ b/cmlogrc.ALH @@ -0,0 +1,17 @@ +# configuration file for cmlog +# Type Title Tag Width +Col Facility facility 45 +Col Time cmlogTime 165 +Col Domain domain 135 +Col Device device 145 +Col Alias message 255 +Col Severity severity 85 +Col Status status 100 +Col Value value 140 +Col Text text 270 +Col Display cmlogDispName 75 +Col Name name 30 +Col User user 50 +Col Host host 50 +# Buffer size for updating the message +ubufsize 1000 diff --git a/current.c b/current.c new file mode 100644 index 0000000..c58fec3 --- /dev/null +++ b/current.c @@ -0,0 +1,234 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* current.c */ + +/************************DESCRIPTION*********************************** + Routines for viewing the current alarm history window +**********************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alh.h" +#include "axArea.h" +#include "cadef.h" +#include "ax.h" + +/* global variables */ +extern char * alhAlarmSeverityString[]; +extern char * alhAlarmStatusString[]; + +/* forward declarations */ +void closeCurrentCallback( Widget w, Widget currentForm, caddr_t call_data); + + +/************************************************************************** + create scroll window for file view +**************************************************************************/ +void currentAlarmHistoryWindow(ALINK *area,Widget menuButton) +{ + Widget popup_shell,title,button; + Widget previous; + Atom WM_DELETE_WINDOW; + int i; + char *app_name; + + if (!area->currentAlarmForm) { + app_name = (char*) calloc(1,strlen(programName)+6); + strcpy(app_name, programName); + strcat(app_name, "-hist"); + + popup_shell = XtAppCreateShell( app_name, programName, + applicationShellWidgetClass, display, NULL, 0); + + free(app_name); + + XtVaSetValues(popup_shell, + XmNtitle, "Alarm Handler: Current Alarm History", NULL); + + /* create current alarm form window */ + area->currentAlarmForm = XtVaCreateManagedWidget("CurrentAlarm", + xmFormWidgetClass, popup_shell, + XmNallowOverlap, FALSE, + XmNuserData, menuButton, + XmNnoResize, TRUE, + NULL); + + /* Modify the window manager menu "close" callback */ + XtVaSetValues(popup_shell, + XmNdeleteResponse, XmDO_NOTHING, + NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(popup_shell), + "WM_DELETE_WINDOW", False); + XmAddWMProtocolCallback(popup_shell,WM_DELETE_WINDOW, + (XtCallbackProc)closeCurrentCallback, + (XtPointer)area->currentAlarmForm); + + /* add close button */ + button = XtVaCreateManagedWidget("Close", + xmPushButtonWidgetClass, area->currentAlarmForm, + XmNtopAttachment, XmATTACH_FORM, + XmNtopOffset, 5, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 5, + XmNuserData, menuButton, + (XtPointer)NULL); + XtAddCallback(button, XmNactivateCallback, + (XtCallbackProc)closeCurrentCallback, + area->currentAlarmForm); + + previous = button; + + /* add title line */ + title = XtVaCreateManagedWidget( + " TIME_STAMP PROCESS_VARIABLE_NAME " + "STATUS SEVERITY VALUE ", + xmLabelGadgetClass, area->currentAlarmForm, + XmNtopAttachment, XmATTACH_FORM, + XmNtopOffset, 10, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, button, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + /* create 10 label widgets */ + for ( i=0;i<10;i++){ + + area->currentAlarm[i] = XtVaCreateManagedWidget( "-----", + xmLabelGadgetClass, area->currentAlarmForm, + XmNmarginHeight, 1, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, previous, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + previous = area->currentAlarm[i]; + } + + /* create a blank line */ + (void)XtVaCreateManagedWidget( " ", + xmLabelGadgetClass, area->currentAlarmForm, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, previous, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtRealizeWidget(popup_shell); + updateCurrentAlarmWindow(area); + + + } else { + + if (XtIsManaged(area->currentAlarmForm)){ + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + XtUnmanageChild(area->currentAlarmForm); + XUnmapWindow(XtDisplay(area->currentAlarmForm), + XtWindow(XtParent(area->currentAlarmForm))); + } else { + XtVaSetValues(menuButton, XmNset, TRUE, NULL); + XtManageChild(area->currentAlarmForm); + XMapWindow(XtDisplay(area->currentAlarmForm), + XtWindow(XtParent(area->currentAlarmForm))); + updateCurrentAlarmWindow(area); + } + } +} + +/************************************************************************** + close Current Alarm History window +**************************************************************************/ +void closeCurrentCallback(Widget w,Widget currentForm,caddr_t call_data) +{ + Widget menuButton; + + XtVaGetValues(currentForm, XmNuserData, &menuButton, NULL); + + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + XtUnmanageChild(currentForm); + XUnmapWindow(XtDisplay(currentForm), + XtWindow(XtParent(currentForm))); +} + +/****************************************************************** + updateCurrent Alarm History strings +*****************************************************************/ +void updateCurrentAlarmString(ALINK *area, time_t *ptimeofday,char *name, +char value[],int stat,int sevr) +{ + int n; + + if ( !area ) return; + n = area->currentAlarmIndex; + sprintf(area->currentAlarmString[n], + " %-24s : %-28s %-10s %-10s %s", + ctime(ptimeofday), + name, + alhAlarmStatusString[stat], + alhAlarmSeverityString[sevr], + value); + n = (n+1)%10; + area->currentAlarmIndex = n; +} + +/****************************************************************** + updateCurrent Alarm History Window +*****************************************************************/ +void updateCurrentAlarmWindow(ALINK *area) +{ + int i,j; + XmString xstr; + + if ( area->currentAlarmForm && XtIsManaged(area->currentAlarmForm) ) { + + j = area->currentAlarmIndex; + for (i=0;i<10;i++){ + xstr = XmStringCreateSimple(area->currentAlarmString[j]); + XtVaSetValues(area->currentAlarm[i], + XmNlabelString, xstr, + NULL); + XmStringFree(xstr); + j = (j+1)%10; + } + } +} + +/****************************************************************** + reset Current Alarm History Window +*****************************************************************/ +void resetCurrentAlarmWindow(ALINK *area) +{ + int i; + + for (i=0;i<10;i++){ + strcpy(area->currentAlarmString[i]," "); + } + area->currentAlarmIndex = 0; + updateCurrentAlarmWindow(area); +} + diff --git a/dialog.c b/dialog.c new file mode 100644 index 0000000..53d13a1 --- /dev/null +++ b/dialog.c @@ -0,0 +1,406 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* dialog.c */ + +/************************DESCRIPTION*********************************** + Creates alh dialogs +**********************************************************************/ + +#include +#include + +#include +#include +#include + +#include "ax.h" + +#define TIME_SIZE 18 + +extern Display *display; +extern int _no_error_popup; + +static Widget warningbox = NULL; + +/* function prototypes */ +static void killWidget(Widget w, XtPointer clientdata, XtPointer calldata); +static void killDialog(Widget w, XtPointer clientdata, XtPointer calldata); +#if 0 +static void logMessageString(Widget w, XtPointer clientdata, XtPointer calldata); +#endif + + +/****************************************************** + Create a fileSelectionBox +******************************************************/ +Widget createFileDialog(Widget parent,void *okCallback,XtPointer okParm, +void *cancelCallback,XtPointer cancelParm,XtPointer userParm, +String title,String pattern,String directory) +{ + XmString Xtitle; + XmString Xpattern; + XmString Xdirectory; + XmString Xcurrentdir=0; + static Widget fileselectdialog = 0; /* make it static for reuse */ + static void *oldOk= NULL; + static void *oldCancel=NULL; + static XtPointer oldOkParm = 0; + static XtPointer oldCancelParm = 0; + char file_sel[]="file_sel"; + + /* parent = 0 means we want to unmanage the fileSelectdialog */ + if (!parent){ + if (fileselectdialog && XtIsManaged(fileselectdialog)) + XtUnmanageChild(fileselectdialog); + return(fileselectdialog); + } + + /* destroy runtimeToplevel fileselectdialog + so we will not have exposure problems */ + if ( parent && fileselectdialog && + XtParent(XtParent(fileselectdialog)) != parent) { + XtDestroyWidget(fileselectdialog); + fileselectdialog = 0; + } + + /* "Open" was selected. Create a Motif FileSelectionDialog w/callback */ + if (!fileselectdialog) { + fileselectdialog = XmCreateFileSelectionDialog(parent, + file_sel, NULL, 0); + XtVaSetValues(fileselectdialog, + XmNallowShellResize, FALSE, + NULL); + XtAddCallback(fileselectdialog,XmNhelpCallback, + (XtCallbackProc)helpCallback,(XtPointer)NULL); + } else { + XtVaGetValues(fileselectdialog, XmNdirectory, &Xcurrentdir, NULL); + if (oldOk) XtRemoveCallback(fileselectdialog,XmNokCallback, + (XtCallbackProc)oldOk ,(XtPointer)oldOkParm); + if (oldCancel) XtRemoveCallback(fileselectdialog,XmNcancelCallback, + (XtCallbackProc)oldCancel ,(XtPointer)oldCancelParm); + } + + Xtitle=XmStringCreateLtoR(title,XmSTRING_DEFAULT_CHARSET); + Xpattern=XmStringCreateLtoR(pattern,XmSTRING_DEFAULT_CHARSET); + if ( !directory && Xcurrentdir ) Xdirectory = Xcurrentdir; + else Xdirectory = XmStringCreateLtoR(directory,XmSTRING_DEFAULT_CHARSET); + + XtVaSetValues(fileselectdialog, + XmNuserData, userParm, + XmNdialogTitle, Xtitle, + XmNdirectory, Xdirectory, + XmNpattern, Xpattern, + (XtPointer)NULL); + + XmStringFree(Xtitle); + XmStringFree(Xpattern); + XmStringFree(Xdirectory); + + XtAddCallback(fileselectdialog,XmNokCallback, + (XtCallbackProc)okCallback, (XtPointer)okParm); + XtAddCallback(fileselectdialog,XmNcancelCallback, + (XtCallbackProc)cancelCallback,(XtPointer)cancelParm); + oldOk = okCallback; + oldCancel = cancelCallback; + oldOkParm = okParm; + oldCancelParm = cancelParm; + + XtManageChild(fileselectdialog); + XFlush(display); + /* + XtPopup(XtParent(fileselectdialog), XtGrabNone); + */ + return(fileselectdialog); +} + +/****************************************************** + createDialog +******************************************************/ +void createDialog(Widget parent,int dialogType,char *message1,char *message2) +{ + XmString str,str1,str2,str3,string,string2; + Widget dialog = 0; + + dialog = XmCreateMessageDialog(parent, "Dialog", NULL, 0); + XtUnmanageChild(XmMessageBoxGetChild(dialog,XmDIALOG_CANCEL_BUTTON)); + XtUnmanageChild(XmMessageBoxGetChild(dialog,XmDIALOG_HELP_BUTTON)); + XtSetSensitive(XmMessageBoxGetChild(dialog,XmDIALOG_HELP_BUTTON),FALSE); + XtAddCallback(dialog,XmNokCallback,killDialog,NULL); + + switch(dialogType) { + case XmDIALOG_WARNING: + str=XmStringCreateLtoR("WarningDialog",XmSTRING_DEFAULT_CHARSET); + break; + case XmDIALOG_ERROR: + str=XmStringCreateLtoR("ErrorDialog",XmSTRING_DEFAULT_CHARSET); + break; + case XmDIALOG_INFORMATION: + str=XmStringCreateLtoR("InformationDialog",XmSTRING_DEFAULT_CHARSET); + break; + case XmDIALOG_MESSAGE: + str=XmStringCreateLtoR("MessageDialog",XmSTRING_DEFAULT_CHARSET); + break; + case XmDIALOG_QUESTION: + str=XmStringCreateLtoR("QuestionDialog",XmSTRING_DEFAULT_CHARSET); + break; + case XmDIALOG_WORKING: + str=XmStringCreateLtoR("WorkDialog",XmSTRING_DEFAULT_CHARSET); + break; + default: + str=XmStringCreateLtoR("Dialog",XmSTRING_DEFAULT_CHARSET); + break; + } + + str1 = XmStringCreateLtoR(message1,XmFONTLIST_DEFAULT_TAG); + str2 = XmStringCreateLtoR(message2,XmFONTLIST_DEFAULT_TAG); + string = XmStringConcat(str1,str2); + + str3 = XmStringCreateLtoR("ALH ",XmFONTLIST_DEFAULT_TAG); + string2 = XmStringConcat(str3,str); + + XtVaSetValues(dialog, + XmNdialogType, dialogType, + XmNdialogTitle, string2, + XmNmessageString, string, + (XtPointer)NULL); + XmStringFree(str); + XmStringFree(str1); + XmStringFree(str2); + XmStringFree(string); + + XtManageChild(dialog); + XFlush(display); +} + +/****************************************************** + createActionDialog +******************************************************/ +void createActionDialog(Widget parent,int dialogType,char *message1, +XtCallbackProc okCallback,XtPointer okParm,XtPointer userParm) +{ + static Widget dialog = 0; /* make it static for reuse */ + XmString str,str1,str2,str3; + static XtCallbackProc oldOkCallback = 0; + static XtPointer oldOkParm = 0; + + if (dialog && XtIsManaged(dialog)) XtUnmanageChild(dialog); + if (!dialogType ) return; + + /* destroy runtimeToplevel dialog so dialog is positioned properly */ + if ( parent && dialog && + XtParent(XtParent(dialog)) != parent) { + XtDestroyWidget(dialog); + dialog = 0; + } + + if (!dialog) { + dialog = XmCreateMessageDialog(parent, "Dialog", NULL, 0); + XtSetSensitive(XmMessageBoxGetChild(dialog,XmDIALOG_HELP_BUTTON),FALSE); + XtAddCallback(dialog,XmNcancelCallback,(XtCallbackProc) XtUnmanageChild,NULL); + + } else { + XtRemoveCallback(dialog,XmNokCallback,oldOkCallback,(XtPointer)oldOkParm); + } + + switch(dialogType) { + case XmDIALOG_WARNING: + str = XmStringCreateSimple("WarningDialog"); + break; + case XmDIALOG_ERROR: + str = XmStringCreateSimple("ErrorDialog"); + break; + case XmDIALOG_INFORMATION: + str = XmStringCreateSimple("InformationDialog"); + break; + case XmDIALOG_MESSAGE: + str = XmStringCreateSimple("MessageDialog"); + break; + case XmDIALOG_QUESTION: + str = XmStringCreateSimple("QuestionDialog"); + break; + case XmDIALOG_WORKING: + str = XmStringCreateSimple("WorkingDialog"); + break; + default: + str = XmStringCreateSimple("InformationDialog"); + break; + } + + str1 = XmStringCreateLtoR("ALH ",XmFONTLIST_DEFAULT_TAG); + str3 = XmStringConcat(str1,str); + + str2=XmStringCreateLtoR(message1,XmSTRING_DEFAULT_CHARSET); + XtVaSetValues(dialog, + XmNuserData, userParm, + XmNdialogType, dialogType, + XmNdialogTitle, str3, + XmNmessageString, str2, + (XtPointer)NULL); + XmStringFree(str); + XmStringFree(str2); + + XtAddCallback(dialog,XmNokCallback,okCallback,okParm); + oldOkCallback = okCallback; + oldOkParm = okParm; + + XtManageChild(dialog); + XFlush(display); + /* + XmUpdateDisplay(dialog); + */ + return; +} + +/****************************************************** + Error message popup +******************************************************/ +void errMsg(const char *fmt, ...) +{ + XmString cstring,cstringOld,cstringNew; + va_list vargs; + static char lstring[1024]; /* DANGER: Fixed buffer size */ + static int warningboxMessages = 0; + int nargs=10; + Arg args[10]; + size_t len; + struct tm * tms; + time_t timeofday; + + timeofday = time(0L); + tms = localtime(&timeofday); + len = strftime(lstring,TIME_SIZE,"%Y/%m/%d %H:%M ",tms); + va_start(vargs,fmt); + vsprintf(&lstring[TIME_SIZE-1],fmt,vargs); + va_end(vargs); + + if(lstring[TIME_SIZE-1] == '\0') return; + + alLogOpModMessage(0,0,&lstring[TIME_SIZE-1]); + + if (_no_error_popup) { + return; + } + + if (warningbox) { + + if (warningboxMessages > 30) return; + + cstring=XmStringCreateLtoR(lstring,XmSTRING_DEFAULT_CHARSET); + XtVaGetValues(warningbox, XmNmessageString, &cstringOld, NULL); + cstringNew = XmStringConcat(cstringOld,cstring); + XmStringFree(cstring); + XmStringFree(cstringOld); + if (warningboxMessages == 30){ + cstring=XmStringCreateLtoR( + "\nOnly first 30 messages are displayed and logged\n", + XmSTRING_DEFAULT_CHARSET); + cstringOld = cstringNew; + cstringNew = XmStringConcat(cstringOld,cstring); + XmStringFree(cstring); + XmStringFree(cstringOld); + } + XtVaSetValues(warningbox, XmNmessageString, cstringNew, NULL); + XmStringFree(cstringNew); + warningboxMessages += 1; + XtManageChild(warningbox); + } else { + XBell(display,50); + XBell(display,50); + XBell(display,50); + cstring=XmStringCreateLtoR(lstring,XmSTRING_DEFAULT_CHARSET); + nargs=0; + XtSetArg(args[nargs],XmNtitle,"ALH Warning"); + nargs++; + XtSetArg(args[nargs],XmNmessageString,cstring); + nargs++; + warningbox=XmCreateWarningDialog(topLevelShell,"warningMessage", + args,nargs); + XmStringFree(cstring); + XtDestroyWidget(XmMessageBoxGetChild(warningbox,XmDIALOG_CANCEL_BUTTON)); + XtDestroyWidget(XmMessageBoxGetChild(warningbox,XmDIALOG_HELP_BUTTON)); + /*XtAddCallback(warningbox,XmNokCallback,logMessageString,NULL);*/ + XtAddCallback(warningbox,XmNokCallback,killWidget,NULL); + warningboxMessages = 1; + XtManageChild(warningbox); + } +} + +/****************************************************** + Fatal error message popup +******************************************************/ +void fatalErrMsg(const char *fmt, ...) +{ + va_list vargs; + static char lstring[1024]; /* DANGER: Fixed buffer size */ + + va_start(vargs,fmt); + vsprintf(lstring,fmt,vargs); + va_end(vargs); + + if(lstring[0] == '\0') return; + + errMsg(lstring); + if (warningbox) XtAddCallback(warningbox,XmNokCallback,exit_quit,NULL); +} + +#if 0 +/****************************************************** + Static callback routine for logging a widget's messageString to opMod log file +******************************************************/ +static void logMessageString(Widget w, XtPointer clientdata, XtPointer calldata) +{ + XmString cstring; + XmStringContext context; + char *lstring; + XmStringCharSet tag; + XmStringDirection direction; + Boolean separator; + + XtVaGetValues(w, XmNmessageString, &cstring, NULL); + if (!XmStringInitContext(&context,cstring)) { + XmStringFree(cstring); + return; + } + + while (XmStringGetNextSegment(context,&lstring,&tag,&direction,&separator)){ + alLogOpModMessage(0,0,lstring); + XtFree(lstring); + lstring=0; + } + if (lstring) XtFree(lstring); + XmStringFree(cstring); + XmStringFreeContext(context); + XtFree(tag); +} +#endif + +/****************************************************** + Static callback routine for destroying a widget +******************************************************/ +static void killWidget(Widget w, XtPointer clientdata, XtPointer calldata) +{ + XtDestroyWidget(w); + if (w == warningbox) { + warningbox = NULL; + } +} + +/****************************************************** + Static callback routine for destroying a widget +******************************************************/ +static void killDialog(Widget w, XtPointer clientdata, XtPointer calldata) +{ + XtDestroyWidget(w); +} diff --git a/documentation/ALH.html b/documentation/ALH.html new file mode 100644 index 0000000..0daee5b --- /dev/null +++ b/documentation/ALH.html @@ -0,0 +1,2029 @@ + + +Alarm Handler User's Guide + + +

Chapter 1: Preface

+ +

Purpose of Document

+ +

This document presents a +description of the functions provided by the Alarm Handler (ALH) and describes +its graphical user interface. The purpose of this guide is to explain how to +use and configure the Alarm Handler.

+ +

Audience

+ +

This guide is written +for individuals who wish to use and understand the Alarm Handler, namely +accelerator operators and accelerator physicists.

+ +

Background/Environment

+ +

The Alarm Handler is +part of the Experimental Physics and Industrial Control System +EPICS) co-developed by Los Alamos National Laboratory +and Argonne National Laboratory. EPICS consists of a set of software components +and tools with which application developers and designers can create an +extremely flexible control system that minimizes the need for custom coding and +helps ensure uniform operator interfaces. The Alarm Handler is one of the EPICS +control system tools.

+ +

EPICS Control System Perspective

+ +

The Alarm Handler +provides an interface between an operator and the EPICS control system +database. The database is the interface +between instrumentation hardware and all the EPICS control system software +tools. This database is distributed throughout a network on I/O Controllers and +contains records that are used to transfer information to and from the attached +instrumentation to the Alarm Handler and other EPICS software tools.

+ +

Database records are +made up of fields of various types. Scan fields specify under what +circumstances a record will be processed. Convert fields determine how to +convert a raw signal to/from engineering units. Device fields are used to +specify the software interface to the device. Operator display fields specify +how to display the record value. Processing fields are used by the run-time +code for processing the record. There are also alarm +fields that are used to specify conditions for alarm and to determine if the +record is in an alarm state. Most fields are accessible throughout the network +by means of the channel access interface +software layer by specifying the record name and the field name. All monitoring +and control operations are performed through the database.

+ +

Alarm Fields

+ +

Each record in the +database includes fields for specifying the record's current alarm condition. +There are two parts to this alarm condition: the alarm status and the severity +of that alarm status. Alarm status and severity values are set and checked +whenever a record is processed. When a new condition is detected, a routine is +called to send a message to each process monitoring this record. The Alarm +Handler is one of these processes.

+ +

Each database record also includes two fields for +specifying the record's current alarm acknowledgment state. The unacknowledged +severity field is the highest severity value of unacknowledged alarms, and the +acknowledge transients field specifies whether transient alarms need to be +acknowledged. A transient alarm is when the record enters alarm state and then +returns to normal before the alarm is acknowledged. When any change to these +fields is detected, a routine is called to send a message to each process +monitoring this record.

+ +

The Alarm Handler filters alarm messages and +displays alarms to the operator hierarchically. The alarm configuration +structure defined in the alarm configuration file is used to determine this +hierarchical display. The Alarm Handler brings alarms to the operator's +attention, logs the alarms, allows the operator to acknowledge alarms, and +gives the operator guidance on handling of specific alarms.

+ +

Document Organization

+ +

Chapter +1 is this Preface describing the users guide. Chapter +2 is an Introduction to the Alarm Handler and describes the scope of the +tool and explains some Alarm Handler terminology. Chapter +3 explains how to invoke the Alarm Handler and describes the command line +options. The Main Window is explained in Chapter 4 and +Chapter 5 contains a description all Main Window menu +functions. The content of an alarm configuration file is described in Chapter 6. An index of terms is available at the end of +the document. Using the alarm configuration mode will be explained in Chapter 7 +of a future version of this document.

+ +
+ +

+Chapter 2: Introduction

+ +

What is the Alarm Handler?

+ +

Definition

+ +

The +Alarm Handler is an interactive graphical application +used primarily by accelerator operators and physicists to display and monitor +EPICS database alarm states. It serves as an interface between an operator and +the EPICS database and it communicates with the database using channel access +function calls. The user interface for the Alarm Handler contains a +hierarchical display of an alarm configuration structure allowing both high +level and detailed views of the alarm configuration structure in one window.

+ +

Availability

+ +

The alarm handler is a +Motif and X11 Window based application written in C language, and it runs on +Unix, Linux, and Windows 98/XP hosts. The Alarm Handler source code is +available via WWW as an EPICS extension.

+ +

Purpose of the Alarm Handler

+ +

The Alarm Handler monitors +alarm conditions of EPICS database records. The primary responsibilities of the +Alarm Handler (ALH) are to:

+ +
    +
      +
    • Bring alarms to the operator's attention.
    • +
    • Provide the operator guidance for handling of specific alarms
    • +
    • Allow the operator to globally acknowledge alarms.
    • +
    • Provide a graphical view of current database alarms
    • +
    • Provide for logging alarms and display of the logged alarm history
    • +
    +
+ +

System Requirements

+ +

The Alarm Handler currently requires either +an IBM personal computer with Windows 95/NT and Hummingbird's +Exceed software or a workstation running a Unix type operating system with X +Windows and Motif Version 1.2 or above. The Alarm Handler also requires the +global alarm acknowledgment in EPICS base Version 3.11 or above.

+ +

Alarm Handler Terminology

+ +

Alarm

+ +

An unexpected change of +state for an EPICS database record. Examples of alarm conditions are:

+ +
    +
      +
    • Deviations from tolerance band
    • +
    • Software or Hardware errors
    • +
    • Loss of communication to hardware or linked records
    • +
    +
+ +

There are two parts to +an alarm: the alarm status and the severity of that alarm status. Alarm status +and severity are set and checked whenever a record is processed. When a change +is detected, a routine is called which sends a message to each process +monitoring this record. The Alarm Handler may be one of these processes.

+ +

Alarm Severity

+ +

The SEVR alarm field in +an EPICS database record specifies the severity of an alarm state. Currently +the alarm severity can take one of the following four values:

+ +

NO_ALARM, MINOR, MAJOR, +INVALID

+ +

Alarm Status

+ +

Each EPICS database +record has a STAT alarm field that specifies the alarm state of the database +record. Currently the status field can take one of more than 20 values, some of +which are:

+ +

READ, WRITE, HIHI, +HIGH, LOW, LOLO, STATE, COS, COMM, ...

+ +

Alarm Channels

+ +

The Alarm Handler +displays alarms for an arbitrary set of channels. Each Alarm Channel refers to +a specific EPICS database record.

+ +

Alarm Groups

+ +

The Alarm Handler +provides a grouping mechanism so that related channels can be grouped together. +An Alarm Group consists of a named set of lower level groups and/or database +channels.

+ +

Error State

+ +

An Alarm Channel will be considered in an error +state if there is a loss of communication between the Alarm Handler and the +channel or if a channel access exception or other error occurs on the channel.

+ +

Local / Global Mode

+ +

The alarm handler can execute in either a local or +global mode. Global mode means that unacknowledged severity and acknowledge transients +states will be determined by the current value of the fields in an EPICS +database record. Local mode means that the unacknowledged severity and +acknowledge transients states are local alh settings. Command line options +determine the execution mode with local mode being the default setting. There +is no way to change between local and global mode during execution.

+ +

Passive / Active State

+ +

The alarm handler can execute +in either a passive (monitor) or active (modify) state. Passive state means +that the alarm handler does not allow alarm acknowledgment and does not allow +changes to acknowledge transients settings. There will be no +channel access puts when executing in a passive state. The passive/active +execution state is determined by a command line option with active state being +the default and there is no way to change the current state during execution.

+ +

Alarm Acknowledgment

+ +

In Global Mode the Alarm +Handler reads all ACKT and ACKS fields of the configured Alarm Channels: +the Alarm Handler starts with +the complete memory of still unacknowledged alarms. These alarms will have to +be acknowledged, even if some may not be active anymore. (If a channel's ACKT +field is set, any transient alarm will be latched and has to be acknowledged +later on.) Global Mode also makes the Alarm Handler write alarm +acknowledgements into the channels using Channel Access, i.e. all other Alarm +Handlers in Global Mode will receive an alarm acknowledgment. Usually, all +Alarm Handlers in the Control Room will run in Global Mode, so that any alarm +has to be acknowledged only on one of the Alarm Handlers.

+ +

In Local Mode, the Alarm Handler starts without +reading open acknowledgements from the channels, all alarm acknowledgements +made will be valid only for this instance of the Alarm Handler. Usually, Alarm +Handlers outside of the Control Room will run in Local Mode.

+ +

Alarm Handler Windows

+ +

The Alarm Handler display consists of two types of +windows, a runtime window and a Main Window. While the Alarm Handler is +executing, the runtime window is always displayed.

+ +

Runtime Window

+ +

The runtime window is a +small icon like window that contains a single button containing the name of the +alarm configuration main Alarm Group. The color +of this button is used to show the highest alarm severity of any outstanding +alarms. Beeping and blinking of the button is +used to show the presence of unacknowledged alarms. Pressing the runtime window +button will open the Alarm Handler Main Window or, if already open, bring the +Main Window to the top of the window stack. The Close or Quit item on the +window manager menu allows the user to exit +the Alarm Handler.

+ +

Main Window

+ +

The Alarm Handler Main +Window is divided into three parts: a menu bar, an alarm configuration display +area, and a message area.

+ +

On the +menu bar, there are selections for pull-down menu +items that perform all the functions of the Alarm Handler.

+ +

The alarm configuration +display area is divided into two major parts: an alarm configuration tree +structure display and an Alarm Group contents +display. The current alarm configuration tree structure appears in the first +area, and a list of the contents of the currently selected Alarm Group from the +alarm configuration tree structure appears in the second area. +Color is used to show alarm severity. A single +character severity code is also provided for +an operator with a monochrome display.

+ + +

The +message area displays the name of the current +configuration file and has indicators to show definitions of the summary alarms +fields for the currently open alarm configuration file.

+ +

Alarm Handler Files

+ +

There are three files +used by the alarm handler while it is executing. They are the +alarm configuration file, the +alarm log file, and the operation modification log file.

+ +

Alarm Configuration File

+ +

The +alarm configuration file is the only file used as +input to the Alarm Handler. This file defines the Alarm Group structure and +takes data in a flexible input format. The alarm configuration +file specifies the Alarm Groups, Alarm Channels, channel masks, hierarchy of +Alarm Groups, and other configuration information. The format and contents of +the alarm configuration file are described in Chapter 6.

+ +

The user can specify the +desired alarm configuration file using a file selection window at Alarm Handler +start-up, or on the command line.

+ +

Alarm Log File

+ +

The Alarm Log output file contains a log of alarm +state changes. For each change of alarm state, channel access connection state, +and read/write access state, the date, time, channel name and current state +values are recorded. The alarm log file is an ASCII file that can be displayed +on any terminal or sent to a printer.

+ +

Operation Modification Log File

+ +

The Operation +Modification Log output file contains a log of alarm acknowledgments and +changes the user has made to the current alarm handler configuration. For each +operator modification the date, time and description of the operator's +modification are recorded.

+ +
+ +

Chapter 3: Starting ALH

+ + +

Path Requirements

+ +

Before invoking the +Alarm Handler for the first time, the path +to the executable and configuration files +must be established. Contact your EPICS administrator to find the locations of +the Alarm Handler executable, alh, and your site's Alarm Handler +configuration input files.

+ +

Environment Variables

+ +

ALARMHANDLER

+ +

The optional environment +variable ALARMHANDLER can be used to point +the Alarm Handler to a desired working directory. If ALARMHANDLER is not +set, the current working directory is assumed. If the alarm configuration file +resides on a different directory +(e.g. /home/cs/appl/ah/dev) +from the current working directory, under UNIX ALARMHANDLER +can be set to point to the desired path by issuing the UNIX c shell command:

+ +

setenv ALARMHANDLER /home/cs/appl/ah/dev

+ +

The user must have read +and write privileges in this directory.

+ +

ALHMAINFONT

+ +

+The environment variable ALHMAINFONT may be used to set the Runtime Window button font +e.g.

+ +

export ALHMAINFONT='-*-utopia-bold-r-normal--0-720-75-75-p-0-*-*'

+ + +

Command Line Syntax

+ +

Once the path is properly +set, invoke the Alarm Handler by executing the command:

+ +

alh

+ +

This command displays a +file selection box in which to specify an alarm configuration file name. The +default path for files is the directory defined by the ALARMHANDLER environment +variable or the current directory and the default alarm handler output file +names are ALH-default.alhAlarm and ALH-default.alhOpmod . +If there is an alarm configuration file in the current directory with the name +ALH-default.alhConfig, it will be used as the input configuration file.

+ +

The Alarm Handler +command has several options and a usage +message similar to the table below will be displayed if you enter: "alh +-help".

+ +

alh [OPTIONS] [Xoptions] [configfile]

+ +

The alarm handler options are:

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-a alarmlogfile Alarm log filename [ALH-default.alhAlarm
-aCMAlarm log using CMLOG
-BMessage Broadcast System
-cAlarm Configuration Tool mode
-caputacktCaput the config file ackt settings to channels + (if global and active)
-DDisable alarm and opMod log output
-debugDebug output will be sent to stdout
-desc_fieldPut DESC field text on alarm log lines
-f filedirDirectory for alarm configuration files [.]
-filter f-opt + Set alarm display filter with f-opt being one of [nau] +
n[0]: no filter +
a[ctive]: show only active alarms +
u[nack]: show only unacknowledged alarms +
-globalGlobal mode (channel ACKS and ACKT fields)
-helpPrint usage text to stdout
-LUse Locking System
-l logdirDirectory for log files [.]
-m maxrecordsAlarm log file maximum records [2000]
-mainwindow Start with Main Window
-noerrorpopupDo not display error popup window (errors are logged)
-O keyLog to database (Oracle)
-o opmodlogfile Opmod log filename [ALH-default.alhOpmod]
-oCMOpMod log using CMLOG
-P keyPrint to TCP printer
-SPassive state (no ca_puts to ACKS and ACKT fields and severity PV)
-s Silent execution (no alarm beeping)
-TAlarm Log Dated output files
-v, -versionPrint version number
-xmlUse XML-ish format for log files
+

+ + +

Default Settings

+ +

The default settings for +ALH (Alarm Handler) are as follows:

+ +
    +
      +
    • Local mode
    • +
    • Active state
    • +
    • Alarm log file maximum records 2000
    • +
    • Directory for files: ALARMHANDLER if defined else current directory
    • +
    • Alarm Configuration File: ALH-default.alhConfig
    • +
    • Alarm Log File: ALH-default.alhAlarm
    • +
    • Operator Modification Log File: ALH-default.opmod
    • +
    • Save New Configuration File: ALH-new.alhConfig
    • +
    • Beeping Status: On
    • +
    • Severity for Beeping: Minor (i.e. any non-zero severity)
    • +
    +
+ +

Command Line Option Descriptions

+ +

Alarm Configuration File

+ +

The ' configfile +' option specifies which alarm configuration input file is to be used. The +default is no configuration file and a file selection window is displayed.

+ +

Alarm Log File

+ +

The '-a alarmlogfile +' option specifies the name of the alarm log file. The default name is +ALH-default.alhAlarm.

+ +

Log alarms into CMLOG system

+ +

The '-aCM' option enables alarm logging into +a CMLOG system. The default is not to use CMLOG. (Note: This option is only available +if the Alarm Handler is compiled with CMLOG support.)

+ +

Message Broadcast System

+ +

The '-B' option enables an operator to send +messages using message broadcasting. The default is no message broadcasting. +When this option is specified a send message menu item appears on the Main +Window menu, and a message input dialog popup appears when the menu item is +selected. The operator can then type in a message that will be sent to other +alh processes when OK is pressed. A popup dialog box containing a sent message +will appear when an Alarm Handler process receives a message.

+ +

Configuration Tool Mode

+ +

The '-c ' option causes the Alarm Handler to +enter the Alarm Configuration Tool mode. The default is to bring up Alarm +Handler mode. The Alarm Configuration Tool mode is used for creating and +editing alarm configuration files. Documentation for this mode will be added to +this guide later.

+ +

Write Configuration File ACKT Settings on Startup

+ +

The ' -caputackt +' option specifies that the Alarm Handler should write the alarm configuration +file ACKT values using channel access puts to the EPICS database records when +the Alarm Handler reads the configuration file. The default is not to write the +alarm configuration file ACKT values.

+ +

Disable Writing

+ +

The ' -D ' option +allows running the Alarm Handler without creating and/or modifying the alarm +log and alarm opmod files. This is useful if one alh process runs without this +option, creating and modifying some fixed named alarm log files and all other +alh process specifying the same file names run with the -D option which does +not allow them to overwrite the alarm log files.

+ +

Debug output

+ +

The '-debug' option specifies that debugging +output should be printed to stdout. The default is not to print debug output.

+ +

Description field

+ +

The '-desc_field' option specifies that .DESC +field text should be printed on alarmLog output lines. The default +is not to print .DESC field text.

+ +

Directory for All Files

+ +

The '-f filedir ' +option specifies the directory for the Alarm Handler input and output files. +The default location is the current working directory.

+ +

Set Alarm Display Filter

+ +

The '-filter f-opt' option sets the initial +alarm display filter for the Alarm Handler (see ->>Menu +Functions->Setup Menu->Display Filter). `f-opt' may be one of `n[o]' +(for no filter), `a[ct]' (show active alarms) or `u[nack]' (show only +unacknowledged alarms). Default is `no', i.e. all Alarm Groups +and channels in the current configuration will be displayed. This +option is particularly useful in combination with `-mainwindow' to start Alarm +Handlers from operator panels.

+ +

Global Mode

+ +

The '-global' options specifies that +the alarm handler should run in a global mode. In global mode an Alarm +Channel's unacknowledged severity and it's acknowledge transients state will be +determined by the current value of the EPICS database record's ACKS and ACKT +field settings. In local mode, the default mode, the unacknowledged severity +and acknowledge transients settings are local to the alarm handler.

+ +

Help

+ +

The '-help' option will print alh command +usage text to stdout.

+ +

Locking System

+ +

The '-L' option activates a file locking +system (based on lockf(), i.e. NFS-safe) making sure that only one of multiple +Alarm Handlers with enabled log writing has access to the log. If the `master' +(i.e. actively logging) process dies, another Alarm Handler will seamlessly +take over logging. Default is not to use this locking mechanism.

+ +

Directory for Log Files

+ +

The '-l logdir' +option specifies the location of the alarm log file and the operation +modification log file. The default location is the current working directory.

+ +

Maximum Alarm Log Records

+ +

The '-m maxrecords' option allows the user +to specify the maximum number of records that the alarm handler will allow in +the alarm log file. If this number of records is reached, new records +will overwrite old alarm records. The default number of records is 2000. +Specifying zero means the file can have an unlimited number of records.

+ +

Start with Main Window

+ +

The `-mainwindow' option makes the Alarm +Handler start with the Main Window instead of the Runtime Window. This is +useful in conjunction with the `-filter f-opt' option to start Alarm Handlers +from operator panels. The default is to start with the Runtime Window.

+ +

Do not use Popup Boxes for Displaying Errors

+ +

The `-noerrorpopup' option tells the Alarm +Handler not to use popup boxes for displaying errors. This is useful for Alarm +Handlers running as overhead displays (and no mouse attached to handle popups). +The default is to use popups.

+ +

Database

+ +

The '-O key' means that the alarm +handler should send log messages to a database (Oracle).

+ +

OpMod Log File

+ +

The -'o opmodlogfile' option specifies the +location of the operation modification log file. The default location is the +current working directory.

+ +

Log Operator Modifications into CMLOG system

+ +

The '-oCM' option enables opmod logging into +a CMLOG system. The default is not to use CMLOG. (Note: This option is only +available if the Alarm Handler is compiled with CMLOG support.)

+ +

TCP Printing

+ +

The '-P' option +allows simultaneously printing of new alarms to the log file and to a TCP +printer (socket connection). The user must specify all three printer values: 'Name:port:colorModel +' (where colorModel is mono,hp_color,...). Currently the printing is done +asynchronously by adding an additional task "alh_printer". (This +option is still under construction and will use pipes in the future)

+ +

Silent Mode

+ +

The '-s' +option specifies that alh should start executing in a silent mode with no +beeping when alarms are present. Setup menu items can be used to change the +startup silence status.

+ +

Passive Mode

+ +

Specifying this '-S' +option means that the alh will execute in a passive (monitor) mode. This +means that alh can not send channel access acknowledgment of alarms and can not +do channel access puts to the acknowledge transients fields and cannot write to +the severity process variable. It is useful for a non-operator alh user.

+ +

AlarmLogDated

+ +

With the '-T' +option, alarmLog file names will have "date" extensions like +YYYY-MM-DD, and log files are automatically switched at midnight. For this +option, there is a Main Window menu browser that is displayed after pressing +View-"Alarm Log File Window". This browser allows searches in the +AlarmLogFile and find all alarms inside of [t1,t2]-diapason containing some +<String>.

+ +

Print Version

+ +

The '-v' +or '-version' option specifies that the +Alarm Handler version number should be printed to stdout.

+ +

XML-ish Log Files

+ +

The '-xml' +option specifies that the Alarm Handler log files should be written in +Extensible Markup Language (XML).

+ +

Xoptions

+ +

When executing on Unix, +the 'alh' command line accepts all X options such as '-bg color_name' +and '-fg color_name' and '-geometry geom_spec'

+ +

Configuration File Selection Window

+ +

If the Alarm +Configuration file is not specified on the command line, a file selection +window is presented so the user can select the desired Alarm Configuration file

+ +

+ +

There are several ways +to select the directory using this window:

+ +
    +
      +
    • Double-click on the appropriate Directories + entry.
    • +
    • Type the directory name in the Filter window and click on Filter .
    • +
    • Type the directory name in the Selection + window and click on OK .
    • +
    +
+ +

Once in the appropriate directory, there are +several ways to select the desired file:

+ +
    +
      +
    • Double-click on the appropriate Files entry.
    • +
    • Click on the appropriate Files entry and click on OK .
    • +
    • Type the file name in the Selection window and click on OK .
    • +
    +
+ +

Cancel ends the +Alarm Handler session.

+ +

Help has not been +implemented in this release.

+ +

Runtime Window

+ +

Once an Alarm +Configuration file has been selected, the Runtime Window is displayed +on the user's screen as a small icon like window. This window contains +one button labeled with the name of the Alarm Configuration file's Main Alarm +Group (or the Main Alarm Group's alias if it was defined) followed by the +group's Current Mask Summary characters if the mask contains characters +other than "-".

+ +

+ +

The +color of the button indicates the highest outstanding +alarm severity level in the active alarm configuration.:

+ +
    +
      +
    • White: Invalid Alarm
    • +
    • Red: Major Alarm
    • +
    • Yellow: Minor Alarm
    • +
    • Background color: NO Alarm
    • +
    +
+ +

There will be beeping and +the button will blink to indicate the presence of unacknowledged alarms.

+ +

Exiting the Alarm Handler

+ +

To exit the Alarm Handler, +use the Window Manager Menu on +the Runtime Window and choose the Close menu item.

+ +

+ +

This will bring up the +Alarm Handler Exit dialog window.

+ +

+ +

Click on OK to exit the Alarm Handler.

+ +

Click on Cancel +to return to the Alarm Handler.

+ +

Help has not been +implemented in this release.

+ +

Displaying the Main Window

+ +

Click the Runtime window +button to open the Alarm Handler Main window or, if the Main window is already +open, clicking the button will bring the Main window to the top of the window +stack. This window contains the hierarchy of Alarm Groups and Alarm Channels +(Process Variables) being monitored. The left half of the window +contains the tree-structure of the Alarm Group, and the right side contains the +contents of the selected Alarm Group. This window will be discussed in detail +in the next chapter.

+ +

+ +
+ +

Chapter 4: Main Window

+ +

Main Window Description

+ +

When the Runtime Window button is clicked, the Main Alarm +Handler window. is displayed. The Alarm Handler Main Window is divided into two +major parts: an alarm configuration tree structure display and an Alarm Group +Contents display. This window also contains a menu +bar and a message area.

+ +

+ +

This window shows the +hierarchy of Alarm Groups and Alarm Channels (EPICS database records) +being monitored. The left half of the +window contains the tree-structure display of +Alarm Groups, and the right side displays the contents of the tree-structure +display's currently selected Alarm Group.

+ +

Menu Bar

+ +

The Alarm Window menu +bar provides menu selections for all the functions of the alarm handler and +also gives users a second way to access some functions.

+ +

Alarm Configuration Tree Structure Display

+ +

The current alarm configuration +tree structure of Alarm Groups +is graphically displayed as Group Summary Lines which are +described in Group Summary Line. Buttons on the tree +structure display allow the user to expand or deflate the alarm configuration +tree structure.

+ +

Each group name in the +configuration tree structure is displayed on a separate line. The following +items appear in each group line of the tree structure display.

+ +
    +
      +
    • Single character color coded acknowledgment button
    • +
    • Single character color coded severity code
    • +
    • Group name selection button
    • +
    • Optional subgroups arrow button
    • +
    • Optional guidance button
    • +
    • Optional related process button
    • +
    • Current mask summary
    • +
    • Optional Group Beep Severity character
    • +
    • Alarm severity summary
    • +
    +
+ +

The configuration tree +structure display has a scrolling/paging facility and a display resize +facility. This allows users to view an alarm configuration tree structure too +large to display on one screen.

+ +

Alarm Group Contents Display

+ +

The user will be able to +choose any Alarm Group for display by pressing the Alarm Group name button from +the configuration tree structure display. Selecting an Alarm Group will cause +the Alarm Group contents display to show one level of the alarm subgroups and +the Alarm Channels associated with the selected group.

+ +

The Alarm Group contents +display for the currently selected Alarm Group contains +group summary lines for each alarm subgroup followed +by channel status lines for each Alarm Channel +in the selected Alarm Group.

+ +

Each subgroup or channel +name in the summary line is displayed with a color identifier indicating +whether the name is an Alarm Group name or a channel name.

+ +

The Alarm Group display +has a scrolling/paging facility to allow users to view an Alarm Group too large +to display in one screen.

+ +

Each channel status line contains:

+ +
    +
      +
    • Single character color coded acknowledgment button
    • +
    • Single character color coded severity code
    • +
    • Channel name selection button
    • +
    • Optional guidance button
    • +
    • Optional related process button
    • +
    • Current mask
    • +
    • Optional Channel Beep Severity character
    • +
    • Current status and severity
    • +
    • Highest unacknowledged severity
    • +
    +
+ +

Message Area

+ +

The message area shows +the current execution mode (local or global), the current execution state (passive +or active), the name of the current configuration file. It also contains +buttons to silence alarms, and explanatory descriptions of the mask +abbreviation codes and status data which appear in the group summary and +channel status lines.

+ +

There are two Silence buttons which toggle beeping on or off. +The Silence Current button turns off current +alarm beeping until a new alarm occurs. The Silence +One Hour button toggles on/off beeping of current and future alarms for one +hour. When pushed in, beeping is turned off, when out, beeping is on. Beeping +occurs only when there are unacknowledged alarms. The main window background +color is changed to pink when Silence One Hour is active.

+ + +

Group Summary Line

+ +

This display line +summarizer the status of all alarms for the group named in this line and all +lower level groups. The group summary display consists of the following items:

+ +

Acknowledgment Button

+ +

A one-character +acknowledgment button is activated only if an +unacknowledged alarm is present for the group and the alarm handler is +executing in active (modify) state. This button is color-coded +representing the highest severity unacknowledged alarm as follows:

+ +
    +
      +
    • White: V - Invalid Alarm
    • +
    • Red: R - Major Alarm
    • +
    • Yellow: Y - Minor Alarm
    • +
    • Background color - No Alarm
    • +
    +
+ +

This button describes +the highest severity of unacknowledged alarms for this group and all associated +subgroups.

+ +

Clicking on this button +while alh is executing in active state will send channel access alarm +acknowledgments to all Alarm Channels +associated with the group. It has the same effect as individually +acknowledging each channel in an unacknowledged alarm state.

+ +

Single Character Severity Code

+ +

A one-character severity +display code. It is present only if at least one channel associated with the +group is in alarm or in an error state. It is color-coded +and represents the highest severity outstanding alarm as follows:

+ +
    +
      +
    • White: E - Error state
    • +
    • White: V - Invalid Alarm
    • +
    • Red: R - Major Alarm
    • +
    • Yellow: Y - Minor Alarm
    • +
    +
+ +

The code shows the +highest severity unacknowledged alarm for this group and all it's subgroups.

+ +

Group Name Selection Button

+ +

ALH allows the operator +to choose any Alarm Group by selecting the Group Name button on the +group summary line. The result is to display one level of the contents +associated with the selected group. This group also becomes the currently +selected group.

+ +

+ALH allows drag and drop of the alarm group name text associated with the +Group Name Selection Button. This may be used to view the alarm group name +when an alias is displayed. The user should hold down the middle (second) +mouse button when the mouse cursor is positioned over a Group Name Button. +A text box containing the alarm group name will appear. When the user moves +the mouse with the mouse button still depressed, the box will follow the mouse +around until the user finally releases the button. The alarm group name text +will then be dropped into the release location which must be a valid drop +location.

+ +

Current Mask Summary

+ +

The Current Mask Summary +Display is a five character mask display. Each character is a"-" or +one of the following:

+ +
    +
      +
    • C: Cancel Alarm
    • +
    • D: Disable Alarm
    • +
    • A: NoAck Alarm or H: NoAck 1hr Timer Active
    • +
    • T: NoAck Transient Alarm
    • +
    • L: NoLog Alarm
    • +
    +
+ +

Mask values are described +in Alarm Channel Mask. If the current mask for any channel +connected with this group or any subgroup has the above mask condition set, the +corresponding character is displayed, otherwise the character "-" is +displayed. For example the string "--A--" +means that at least one channel has the NoAck mask set +and that no channels have any other masks set.

+ +

Alarm Severity Summary Counts

+ +

The alarm summary count +display shows the total number of channels in alarm and in an error state for +this group and all its subgroups. This summary consists of a set of five +fields:

+ +

(ERROR, INVALID, MAJOR, +MINOR, NOALARM)

+ +

Each field value +indicates the total number of channel alarms with the specified severity in the +associated group and all it's subgroups.

+ +

 

+ +

Alarm Channel Status Line

+ +

The channel status +display is a line appearing on an Alarm Group Contents Window containing the +following items:

+ +

Acknowledgment +Button

+ +

A one character +acknowledgment button. It is activated only if an unacknowledged alarm is +present for the channel and the alarm handler is executing in active (modify) +state. It is color coded, and represents the +highest severity unacknowledged alarm as follows:

+ +
    +
      +
    • White E - Error state
    • +
    • White: V - Invalid Alarm
    • +
    • Red: R - Major Alarm
    • +
    • Yellow: Y - Minor Alarm
    • +
    • Background color - No Alarm
    • +
    +
+ +

Clicking on this button +while alh is executing in active state will send a channel access alarm +acknowledgments to the Alarm Channel. A warning popup dialog with the message +that alarm acknowledgment is not allowed in passive state will appear if the +alarm handler is executing in passive (monitor) state.

+ + +

Severity Code

+ +

The severity code +character is present only if the channel is in alarm or in an error state. In this +case, it is a color coded letter which represents the severity of the alarm as +follows:

+ +
    +
      +
    • White: E - Error state
    • +
    • White: V - Invalid Alarm
    • +
    • Red: R - Major Alarm
    • +
    • Yellow: Y - Minor Alarm
    • +
    • Background color - No Alarm
    • +
    +
+ +

Channel Name Button

+ +

This button contains the database record name +associated with the channel or the alias text if an alias is defined for this +channel. The button is color coded in gray so that an operator can easily +distinguish channels from groups. Selecting this button makes the channel +the currently selected item.

+ +

+ALH allows drag and drop of the record name text associated with the Channel +Name Selection Button. This may be used to view the database record name +when an alias is displayed. The user should hold down the middle (second) +mouse button when the mouse cursor is positioned over a Channel Name Button. +A text box containing the record name will appear. When the user moves +the mouse with the mouse button still depressed, the box will follow the mouse +around until the user finally releases the button. The alarm channel name text +will then be dropped into the release location which must be a valid drop +location.

+ +

Current Mask

+ +

The mask field contains +a five-character display showing the settings of the channel's current mask. +Each character is either a "-" or one of the following:

+ +
    +
      +
    • C: Cancel
    • +
    • D: Disable Alarm
    • +
    • A: NoAck Alarm
    • +
    • T: NoAck Transient Alarm
    • +
    • L: NoLog Alarm
    • +
    +
+ +

Masks are described in +Alarm Channel Mask

+ +

Alarm Status and Severity

+ +

Following the current +mask characters are the channel's current alarm status and severity and the +highest unacknowledged alarm severity. Current status and severity is present +only if the channel is in an alarm state. Highest unacknowledged alarm severity +is present only if an unacknowledged alarm is present.

+ +
+

Chapter 5: Menu Functions

+ + +

Main Window Menu Bar

+ +

The Main Window menu bar +contains five pull-down menu items: File, Action, View, Setup, and Help.

+ +

File Menu Commands

+ +

The File menu has three +command items: Open, Save As, and Close.

+ +

+ +

Open

+ +

To open an existing alh configuration file, use the +"File Open" menu item.

+ +

+ +

This brings up a +standard file selection dialog, which allows +the user to move around an existing directory structure to find the file to +open.

+ +

To aid the user, the +file selection box initially displays all files in the directory which end in +".alhConfig".

+ +

Save As

+ +

The " +Save As" menu item, allows the user to save the +current alarm configuration structure and current alarm configuration settings +to a new or existing file. A dialog appears which prompts the user to supply +the name of a file to write to. If the user gives the name of an existing file, +another popup dialog will give a warning and ask the user if the existing file +can be overwritten.

+ +

+ +

Close

+ +

Selecting the Close item +on the File menu can close the alh Main Window. This Main Window can be +redisplayed again with a mouse click on the runtime window button.

+ +

Action Menu Commands

+ +

The Action Menu provides +selections which affect the currently selected Alarm Group or Channel. The +action selections "Acknowledge Alarm", "Display Guidance", +and "Start Related Process" can also be accomplished by clicking +buttons on the tree structure or group contents display.

+ +

+ +

Acknowledge Alarm

+ +

Alarm acknowledgment is +only allowed while the alarm handler is executing in active (modify) state. The +Alarm Handler user can acknowledge an alarm for the currently selected Alarm +Group or Channel by selecting the "Acknowledge Alarm" item on the +Action menu. Selecting this item for an Alarm Group acknowledges all Alarm +Channels associated with the group. It has the same effect as acknowledging +each channel individually.

+ +

When executing in global mode the Alarm Handler +performs an alarm acknowledgment by sending a channel access alarm acknowledgment +command to the channel and logging the alarm acknowledgement to the operator +modification log file. The alarm acknowledgment indicators (color, blinking, +and beeping) will change only after a channel access alarm event with the +modified unacknowledged severity is received. Other executing alarm handler +processes and other EPICS tools monitoring alarm events will also receive this +alarm event.

+ +

When executing in local mode the alarm +acknowledgment indicators (color, blinking and beeping) and the local unacknowledged +severity level setting will change to reflect a local alarm acknowledgment and +the alarm acknowledgement will be logged to the operator modification log file.

+ +

Display Guidance

+ +

When "Display  +Guidance" is selected, associated guidance text +lines for a selected Alarm Channel or Alarm Group will be displayed. Guidance +text is intended to suggest possible reasons why this group or channel might +alarm and actions that might remove the alarm condition. This menu item is +inactive if guidance information is not available for the currently selected +Alarm Group or Alarm Channel.

+ +

+ +

The guidance text +display is a popup window displaying lines of ascii text if text was specified +in the alarm configuration file. If a URL address was specified in the +configuration file, Netscape will be invoked and display the text at the +specified URL address.

+ +

Start Related Process

+ +

Selecting "Start +Related Process" will initiate execution of an Alarm Group or Alarm +Channel's related process which was specified in the alarm configuration file. +This item will be inactive if a related process was not specified for the +currently selected Alarm Group or Alarm Channel.

+ +

Force Process Variable

+ +

This item displays a +dialog box that allows the operator to change values of the Force Process +Variable. The Force Process Variable is described in a later chapter. The user +can change the name of the Force PV, the values of the Force Process Variable +which will cause the Alarm Channel masks to be set and reset, and the actual +mask the Force Process Variable will force on the group. The user can also +disable and enable the Force PV. The force value must be set to a value different +than the reset value.

+ +

+ +

There are four action +buttons on this dialog box: Apply, Cancel, Dismiss, and Help. The Apply button +will accept and apply the user entered changes. The Cancel button will discard +the user entered changes in this dialog box and reset them to the original +values. The Dismiss button will close this popup dialog, and the Help button +will display a Force PV help information dialog.

+ +

Force Mask

+ +

Selecting "Force +Mask" will popup a dialog box which allows the operator to change the mask +for the currently selected group or channel. Changing a group mask will +actually change the mask of all Alarm Channels +within that group. Three masks are displayed: 1) the current mask, +2) the reset mask, valid for Alarm Channels only, which is the mask specified +in the alarm configuration file, and 3) the mask to force, which the user +defines by pressing one or more of the 5 state buttons below the mask.

+ +

. +

+ +

The mask to be used for +forcing (5 characters) may be any combination of -,C,D,A,T,L

+ +

There are four action +buttons on this dialog box: Apply, Reset, Dismiss and Help. The Apply button will +set the mask of all the Alarm Channels +within this group to the mask as shown in the Mask line. The Reset +button will reset the mask of each channel within this group to its own default +mask defined in the alarm configuration file. The Dismiss button will cancel +the force mask option and close the dialog window. The Help button will give +force mask help information.

+ +

Modify Mask Settings

+ +

This menu item allows +the operator to force or reset a specific bit of the current mask. For example, +if the operator chooses "Add" in the "Add/Cancel Alarms" +line then the Add/Cancel field of the current mask for all channels in the +group are forced into the "Add" event state. Similarly choosing +"Cancel" cancels the channel access add event state for all the +channels. If "Reset" is chosen, the Add/Cancel field of the current +mask for each channel in the group reverts to the default state defined in the +active configuration file. Mask values are described in a later chapter.

+ +

+ +

Beep Severity

+ +

This menu item gives the operator the +ability to change the beep severity on individual +channels or groups. A beep severity indicator will appear +after the mask on the group (highest existing) and channel lines. +The beep severity indicators are E=error, V=invalid, R=major, Y=minor. +Beep Severity can be changed to MINOR, MAJOR, INVALID, or ERROR. +If beep severity is set to MINOR,then MINOR, MAJOR, +INVALID, and ERROR unacknowledged alarms will cause beeping. The -s command line +option, silent execution, will override all menu and config file beep severity +settings.

+ +

+ +

NoAck for One Hour

+ +

This menu item gives the operator the +ability to set the noAck mask field of a group or channel to +No Acknowlegment Necessary for one hour and have it automatically +set to the reset value (config file value) after the hour expires. +An "H" will be put into the noAck position of the mask on the group +or channel line during the noAck hour. When a no-Ack timer is created, +it will cancel any existing timers in any subgroups and channels. +When a timer expires it will not reset any subgroups or channels that +have an existing (i.e. more recent) timer.

+ +

+ +

Message Broadcasting

+ +

The "Send Message" menu item allows alarm +handler operators to send and receive messages to other alarm handler +operators. A message input dialog popup appears when the "Send +Message" menu item is selected. The operator can then type in a message +that will be sent to other alh processes when OK is pressed. A popup message +dialog containing the sent message will appear on other Alarm Handler processes +when they receive the message.

+ +

+ +

+ +

View Menu Commands

+ +

The View menu allows the +user to change the view of Alarm Groups +in the current alarm configuration tree structure display. This +menu also provides options for viewing the current working configuration file, +alarm log file, and operation modification file in scrolled windows.

+ +

+ +

The View menu allows +viewing of logged events while they take place. A user can simultaneously view +both the alarm log file and the operator modification log files. When View is +chosen, the sub-menu is presented.

+ +

Expand One Level

+ +

The user selects this +menu item to expand a collapsed the currently selected Alarm Group to +graphically display one level of its alarm subgroups on the alarm configuration +tree display.

+ +

Expand Branch

+ +

The user can choose this +item to expand the currently selected collapsed Alarm Group in the alarm +configuration tree display to graphically show all levels of its subgroups on +the alarm configuration tree structure display.

+ +

Expend All

+ +

The user uses this menu +item to expand all collapsed groups in the configuration tree structure display +to graphically show all the groups and subgroups in the current alarm +configuration.

+ +

Collapse Branch

+ +

The operator selects +this item to collapse the currently selected expanded group in the alarm configuration +tree to remove all its groups and subgroups from the graphical tree display.

+ +

Current Alarm History Window

+ +

The operator chooses +this menu item to continuously display the current alarm history a display +window containing the 10 most recent alarms. This display will be updated as +alarms occur.

+ +

+ +

Configuration File

+ +

Selecting +"Configuration File" brings up a scrolled window that displays the +contents of the current configuration file. If INCLUDE lines are present +the contents of the included files are recursively displayed.

+ +

+ +

Start CMLOG Log Browser

+ +

Selecting this menu item will +invoke a separate CMLOG browser process that allows +browsing all records logged to the CMLOG system.

+ +

Alarm Log File Window

+ +

Selecting "Alarm +Log File" brings up a scrolled window displaying time stamped alarm events +in the alarm log file. Any new alarms logged into the alarm log file appear +simultaneously in this window.

+ +

+ +

The date and time, Alarm +Channel name, alarm status, alarm severity, and channel value are displayed +when the Alarm Handler is executing in local mode. The highest unacknowledged +severity and the acknowledge transients field values are also logged if the +Alarm Handler is executing in global mode.

+ +

Browser for Alarm Log

+ +

+ +

Operation Log File Window

+ +

Selecting +"Operation Log File" brings up a scrolled window showing the current +content of the Operation Modification Log file. This file contains a log of +time stamped operator configuration modification events. Any newly logged +operation events appear simultaneously in this window. +The top level Alarm Group name appears on each log line. +

+ +

+ +

ALH does not allow an +operator to view a log file that exceeds 1 Megabyte. When the log file exceeds +1 Megabyte, a new log file must be used in order for an operator to be able to +view the log process within the ALH.

+ +

Browser for Operation Log

+ +

+ +

Group/Channel Properties Window

+ +

The Alarm Handler allows +the operator to display all the current configuration settings for any selected +Alarm Group or Alarm Channel.

+ +

+ +

Setup Menu

+ +

The Setup menu provides +the option of overriding initial settings for the alarm configuration, the +alarm log, and the operation modification files.When this menu is selected, the +Setup sub-menu, is presented

+ +

If one of the file +options is chosen, a file selection dialog popup window appears and the +operator is allowed to choose a new file. The operation of the file selection +box is described in +Configuration File Selection Window. + The file selection changes are always logged in the +operation modification file.

+ +

+ +

Display Filter

+ +

The user is allowed to +set an alarm filter to display active alarms only. When the filter is set to +Active Alarms Only, only those groups or channels with an outstanding alarm +will be displayed. When the filter is set to Unacknowldged Alarms Only, only those +groups or channels with an outstanding unacknowledged alarm will be displayed. +When the selection is set to No Filter, all Alarm Groups +and Alarm Channels in the current configuration will be available for display.

+ +

ALH Beep Severity

+ +

The operator can specify +the beep condition. The beep condition is the minimum alarm unacknowledged severity +necessary for beeping. The default startup value is MINOR, or a startup severity can +be specified in the alarm configuration file. The ALH Beep Severity can be changed to +MINOR, MAJOR, or INVALID. If the beep condition is set to MINOR,then MINOR, MAJOR, +INVALID, and ERROR unacknowledged alarms will cause beeping. The -s command line +option, silent execution, will override all menu and config file beep severity +settings.

+ +

+ +

New Alarm Log File

+ +

The alarm log file contains +the log of alarm changes of states. The Alarm Handler allows the operator to +specify an alarm log file name that differs from the current setting. If it +does not exist, it will be automatically created. All new alarm state changes +will be logged to this file.

+ +

New Operation Modification Log File

+ +

The Alarm Handler allows +the operator to specify an operation modification log file that differs from +the current setting. If it does not exist, it will be automatically created by +ALH. All subsequent operation changes will be logged to this new operation +modification file.

+ +

Help Menu

+ +

The Help menu item +will display this "Alarm Handler User Guide" +when selected.

+ +

When the About menu item is chosen, +information about the current version of the alarm handler +is displayed.

+ +
+ +

+Chapter 6: Alarm Configuration File

+ +

Configuration File Description

+ +

The alarm configuration +file is the file used as input to the Alarm Handler. This file defines the +Alarm Group structure and takes data in a flexible input format. The alarm configuration +file, which can be prepared via any text editor, defines a complete Alarm Group +structure composed of subgroups and channels. The arrangement of channels and +subgroups follow the standard tree structure. The subgroups always terminate at +channels. The only input format constraint is that the definitions must be in +hierarchical order. That is, after a group is defined in the configuration file +as belonging to a parent group, all its subgroups and channels must be defined +in the configuration file before a new group belonging to the same parent group +can be defined. There can be only one top-level group (main group) and this +group must have NULL as the parent group name. For each group or channel, a set +of input specifications is used to define special events to be taken care of at +start-up time.

+ +

File Name

+ +

When opening a new configuration file, +".alhConfig" will be used as the default suffix. +The default file name for the alarm configuration file is +ALH-default.alhConfig.

+ +

Input Format

+ +

The configuration file +statements for a given group or channel takes flexible input format which can +consist of the following items:

+ +

GROUP parentName GroupName
+$HEARTBEATPV heartbeatPVName <value> <seconds>
+CHANNEL parentName ChannelName <mask>
+INCLUDE parentName fileName
+$ACKPV ackPVName ackValue
+$FORCEPV forcePVName forceMask <forceValue> <resetValue>
+$FORCEPV CALC forceMask <forceValue> <resetValue>
+$FORCEPV_CALC <expression>
+$FORCEPV_CALC_A <PVNameA>
+...
+$FORCEPV_CALC_F <PVNameF>
+$SEVRPV sevrPVName
+$GUIDANCE
+$END
+$GUIDANCE urlAddress
+$ALIAS anyValidTextString
+$COMMAND anyValidCommand
+$SEVRCOMMAND severityChangeValue anyValidCommand
+$STATCOMMAND alarmStatusStringValue anyValidCommand
+$ALARMCOUNTFILTER inputCount inputSeconds
+$BEEPSEVERITY ALHbeepSeverity
+$BEEPSEVR GroupOrChannelBeepSeverity

+ +

Input syntax notes:

+ +
    +
      +
    • The fields enclosed in <> are optional.
    • +
    • Blanks can be used to separate the fields for improved readability.
    • +
    • The GROUP or CHANNEL line must be first line in a set.
    • +
    • Lines starting with "#" are comments.
    • +
    • Lines starting with "$" are optional.
    • +
    • The [$GUIDANCE ... $END] must be entered as a set +if text guidance is present.
    • +
    +
+ +

Heartbeat Process Variable

+ +

The line starting with $HEARTBEATPV is optional. +It is required only when a user wants a monitored pv to show weather or not +ALH is running. If the $HEARTBEATPV line is present, ALH will do CA puts of +the specified value to the specified pv at the specified rate (in seconds). +The heartbeatPVName must be an existing PV in the EPICS database and can be +specified as <channel_name>.<field_name>. +

+ +

Group or Channel

+ +

A set of group or channel lines must appear +in the alarm configuration file. These lines define the Alarm +Group structure. The first line is the top level Alarm Group definition. +There can be only one top-level Alarm Group and this Alarm Group must have +NULL as the parent group name. Group or Channel lines must start with the +keyword GROUP or CHANNEL. The GroupName is the name of a user specified +Alarm Group. The ChannelName must be the name of a specific record defined +in an EPICS database. The length of a GroupName or ChannelName must not +exceed 28 characters. The parentName is the name of the parent Alarm +Group. There is no restriction on the number of group definitions.

+ +

GROUP parentName GroupName

+ +

The channel <mask> is optional and defaults to no +mask (i.e. -----). It is required only for a channel with a non default mask +setting. The detailed description of mask settings is given in +Alarm Channel Mask in this Chapter.

+ +

CHANNEL parentName ChannelName <mask>

+ +

Include File

+ +

The line starting with +INCLUDE allows a user to designate, within his alarm configuration file, the +name of another alarm configuration file to be read by the Alarm Handler at +runtime. The main Alarm Group of the designated file will become a child group +of the parentName group specified on the INCLUDE line.

+ +

INCLUDE parentName fileName

+ +

Acknowledge Process Variable

+ +

The line starting with $ACKPV is optional. +It is required only when a user wants to write a user specified value +(ackValue) to an acknowledge process variable (ackPVName) when a +channel's alarm is acknowledged. The acknowledge Process variable +must be defined in the IOC database and is specified as +<record_name>.<field_name>. Whenever the channel's alarm is +acknowledged, the acknowledge value (ackValue) is written to the +acknowledge process variable via a channel access put (ca_put) request. +Writes to an acknowledge process variable are done only when the alarm +handler is in global active mode. +

+ +

$ACKPV ackPVName ackValue

+ +

Force Process Variable

+ +

The lines starting with +$FORCEPV are optional. They are required only when a user wants to let ALH automate +changing an alarm group or channel's mask values by monitoring an EPICS database +process variable or by monitoring the value of a calulated expression based on PV values.

+ +

+The first method is to monitor a single EPICS database process variable. +Only only one input line is required. This line defines the forcePVName (process +variable to be monitored), forceMask, forceValue, and resetValue. The forcePVName +must be an existing PV in the EPICS database and can be specified as +<channel_name>.<field_name>. Whenever the value of the force process +variable changes to be the same as the forceValue, the Alarm Group or Channel +mask will be set to the forceMask. For an Alarm Group, this means that masks of +all the channels in the group and its subgroups are set to the forceMask. +Whenever the value of the force process variable changes to be the same as the +resetValue, these channel masks are set to their default values. The forceValue +must be different from the resetValue. The default setting is forceValue = 1, +and resetValue = 0. A "NE" can be used in the resetValue field to reset the +masks when the value of the force process variable no longer equals the force value. +Alarm Handler menu items exist which allow the user to enable/disable the Force PV, +change the name of the Force PV, and change the Force Process Variable values. +The force PV test uses type double for forceValue, resetValue and pv value. +

+ +

$FORCEPV forcePVName forceMask <forceValue> +<resetValue>

+ +

+The second method is to monitor the value of a calculated expression. This +requires multiple Force PV CALC input lines to define the expression. +This CALC facility allows algebraic, relational, and logical +operations on up to 6 pv values. The result of the expression +is compared to the forcePV forceValue and resetValue to determine +whether or not to set group/channel masks. +

+ +

+To specify a forcpePV calculation expression in the alhConfig +file you create the $FORCEPV record as before but you specify +"CALC" instead of a PV name. Then you add a new $FORCEPV_CALC +line in which you specify the calculation expression in a +manner similar to the calc record expression. In fact alh +uses the same code as the calc record to evaluate the +expression. You specify the expression using A, B, ... instead +of the pvnames. Then you add $FORCEPV_CALC_A through +$FORCEPV_CALC_F lines to specify the pv names. (You can also +specify constant values on these lines.) +The Alarm Handler ForcePV dialog window allows users to specify +or change the ForcePV CALC data. +

+ +

+An example of the alhConfig file lines for a calculation +forcePV is +

+ +

+ $FORCEPV CALC ---TL 18.321 NE
+ $FORCEPV_CALC A+B+C
+ $FORCEPV_CALC_A jba:alh5
+ $FORCEPV_CALC_B jba:alh6
+ $FORCEPV_CALC_C 5.321
+ +

+ +

+The expression is evaluated using type "double" for all pv +values and constants. +

+ + + +

Severity Process Variable

+ +

The line starting with +$SEVRPV is optional. It is required only when a user wants to write the +severity value of a group or channel to a process variable. The sevrPVName must +be defined in the IOC database and is specified as +<channel_name>.<field_name>. Whenever the group or channel severity +changes, the new severity value is written to the severity process variable via +a channel access put (ca_put) request. Writes to a severity process variable +are done only when the alarm handler is in global active mode. +The value -1 is written to the servrity PV when the group or channel is disabled. +

+ +

$SEVRPV sevrPVName

+ +

Guidance

+ +

The lines starting with +$GUIDANCE are optional. They are required only when a user wants to display +alarm guidance information for a group or channel. The $GUIDANCE line may be +followed by a set of ascii guidance text lines with an $END line to terminate +the guidance text, or alternatively, the +$GUIDANCE line may contain a url address.

+ +

$GUIDANCE

+

<text lines>

+

$END

+ +

or

+ +

$GUIDANCE urlAddress

+ +

Alias

+ +

The line starting with +$ALIAS is optional. It is required when it is desired that the alarm handler +display the specified alias text string in places where it would normally +display the Alarm Group or Alarm Channel name.

+ +

$ALIAS   anyValidTextString

+ +

Related Commands

+ +

The line starting with $COMMAND +is optional. It is required only when a user wants to provide the feature of +starting a related process for this group or channel. +When the alh operator clicks on a Process Button for an alarm group or channel +in the alarm handler Main Window display one of two things occurs. +If there was a single related process specified on the $COMMAND line for the +group or channel, that process is invoked. If multiple processes were +specified on the $COMMAND line, a popup menu of the related process +names appears and the related process selected by the user is invoked. +

+ +

A single command is specified as follows:

+

$COMMAND   anyValidCommandSyntax

+ +

Multiple commands are specified with command +names and command strings separated by exclamation points, "!", using the +following syntax

+

$COMMAND   +cmd 1 name!cmd 1 string!cmd 2 name!cmd 2 string!...cmd n name!cmd n string +

+ +

Severity Command

+ +

The line starting with +$SEVRCOMMAND is optional. It is required if a process should be invoked when +the alarm severity value for a group or channel changes. A single group or +channel may have multiple $SEVRCOMMAND lines. This line defines the change in +the severity necessary to start the process and defines the process to be +started.

+ +

Valid severity change values are -

+ +

UP_INVALID, UP_MAJOR, +UP_MINOR, UP_ANY, DOWN_MAJOR, DOWN_MINOR, DOWN_NO_ALARM, DOWN_ANY, UP_ALARM

+ +

Status Command

+ +

The line starting with +$STATCOMMAND is optional and valid only for an Alarm Channel. It is required +only when the alarm handler should start a process when the channel alarm +status becomes a specified value. A single channel may have multiple +$STATCOMMAND lines. This line defines the status value necessary to start the +process and defines the process to be started. Valid alarm status string values +can be found in the EPICS base alarmString.h header file.

+ +

Example alarm status string values are -

+ +

NO_ALARM, READ, WRITE, +HIHI, HIGH, READ_ACCESS, LOLO, LOW, STATE, COS, COMM, WRITE_ACCESS, TIMEOUT, +HWLIMIT, CALC, SCAN, LINK, SOFT, BAD_SUB, UDF, DISABLE, SIMM

+ +

Alarm Count Filter

+ +

The line starting with $ALARMCOUNTFILTER is +optional. It is required only when the alarm handler should filter the +registration of alarms for a channel. This line defines the alarm +count and seconds required for alarm registration. To register as an alarm, a +channel must remain in an alarm state for more than inputSeconds seconds or the +channel must enter into an alarm state from a no-alarm state more than +inputCount times within inputSeconds seconds.

+ +

$ALARMCOUNTFILTER inputCount inputSeconds

+ +

Beep Severity

+ +

The line starting with +$BEEPSEVERITY is optional. It is required only when the alarm handler should +filter the beeping if alarms are present. This line defines the minimum +severity level required for beeping. Beeping will not occur when the highest +outstanding severity is less than the specified severity. Valid severity +values are MINOR, MAJOR, INVALID, and ERROR.

+ +

$BEEPSEVERITY severity

+ +

Sample Configuration File

+ +

+The following listing shows a simple example of an alarm configuration file.
+

+ +

+GROUP NULL MAIN
+$COMMAND medm /home/phoebos/USER/appl/example.adl
+$GUIDANCE
+Line 1 of guidance information about main group
+Line 2 guidance.
+Line 3 guidance.
+$END
+
+GROUP MAIN AAA
+$COMMAND medm /home/phoebos/USER/appl/example2.adl
+$SERVPV SEVR:AI
+$FORCEPV FORCE:AI -D---
+CHANNEL AAA rai_2000
+CHANNEL AAA rai_2001
+
+GROUP MAIN BBB
+CHANNEL BBB rbi_000
+CHANNEL BBB rbi_2000
+
+GROUP MAIN CCC
+CHANNEL CCC rbo_000
+CHANNEL MAIN rbo_001
+

+ +

In this example, the +first group is named MAIN. The MAIN group contains three subgroups ( AAA, BBB, +and CCC) and one channel (rbo-001). The AAA subgroup contains two channels: +rai_2000 and rai_2001. The BBB subgroup contains the two channels: rbi_000 and +rbi_2000. The CCC subgroup contains only one channel: rbo_000.

+ +

In +this example the default mask "-----" is used for every channel. That +is, no masks are specified on the group and channel lines.

+ +

In above example, +$COMMAND and $GUIDANCE options are specified for the MAIN group. The $GUIDANCE +option allows the user to display guidance text in a popup window when the MAIN +group guidance button is pressed. The $COMMAND line option allows a user to +start the display manager, medm, by pressing the MAIN group's related proccess +button.

+ +

In above example, the +$COMMAND, $FORCEPV, and $SEVRPV options are specified for the AAA group. This +$COMMAND option allows a user to open an xterm window from the start related +process button on the AAA group line. The $FORCEPV option tells alh to add an +automatic force mask event for group AAA. If the value of process variable +FORCE:AI becomes 1, then the mask of all the channels in this group will be set +to the forceMask, "-D---". If the value of process variable FORCE:AI +becomes 0, then the mask of all the channels in this group will be reset to +their default mask values. The $SEVRPV option tells alh to record the alarm +severity of group AAA to the process variable SEVR:AI.

+ +

 

+ +

Alarm Channel Mask

+ +

Associated with each +Alarm Channel are two five bit masks (default and current). The current mask +can be changed by force commands or by force process variables. The default +mask is defined in the alarm configuration file. A reset command forces all +associated masks to return to the default values.

+ +

The definition for each +bit in the mask value follows:

+ +

Add/Cancel Alarm

+ +

This mask bit determines if +a channel access add event is active. Add/Cancel means that a ca_add_event +is/isn't active. If ca_add_event is not active for a channel, the IOC will not +send alarm events to the alarm handler for that channel.

+ +

" C" means +cancel and "-" denotes add.

+ +

Enable/Disable Alarm

+ +

Alarms aren't/are +ignored by the alarm handler. Disabling an alarm has the effect of no display +and NoAck. If an alarm is disabled the alarm status and severity are not +displayed. Thus, even though a ca_add_event is in effect, the channel always +appears to the operator to be in the NO_ALARM state. Alarm change of states +will, however, still be logged unless NoLog is in effect.

+ +

+When a pv is enabled after it has been disabled for a while and the pv is +not in alarm state but there are unacknowledged transient alarms +and the alarm handler is running in global mode, an automatic +acknowledgement is sent when the pv is enabled and the auto acknowledgement +is logged in the opMod file if the alarm handler is running in global mode. +

+ +

" D" means +alarm disabled.

+ +

Ack/NoAck

+ +

The operator is/isn't +required to acknowledge alarms.

+ +

" A" means +alarm acknowledgment is not required.

+ +

Ack/NoAck Transient Alarms

+ +

The operator is/isn't required +to acknowledge transient alarms. A transient alarm is one that enters alarm +state and then returns to normal before the operator can acknowledge the alarm. +

+ +

" T" means acknowledgment of transient +alarms is not required.

+ +

Log/No Log Alarms

+ +

Alarms will/won't be +logged.

+ +

" L" means no alarm logging .

+ + +
+ + + + diff --git a/documentation/ALH.title.html b/documentation/ALH.title.html new file mode 100644 index 0000000..3781cd7 --- /dev/null +++ b/documentation/ALH.title.html @@ -0,0 +1,30 @@ + + +
+ +
+
+
+
+Alarm Handler User's Guide<TITLE></A> +<H1>Alarm Handler User's Guide</H1></A> +<BR> +<BR> +<H2>ALH 1.2.23</H2> +<H3>November 2007</H3> +<BR> +<BR> +<BR> +<BR> +<BR> +<BR> +<p><b>Janet Anderson</b></p> +Copyright (c) 2007 UChicago Argonne, LLC <BR> +as Operator of Argonne National Laboratory. <BR> +Copyright (c) 2002 Deutches Elektronen-Synchrotron <BR> +in der Helmholtz-Gemelnschaft (DESY). <BR> +Copyright (c) 2002 Berliner Speicherring-Gesellschaft <BR> +fuer Synchrotron-Strahlung mbH (BESSY). <BR> +</CENTER> + +</html> diff --git a/documentation/Makefile b/documentation/Makefile new file mode 100644 index 0000000..50c4b3c --- /dev/null +++ b/documentation/Makefile @@ -0,0 +1,66 @@ +# Makefile for generating published alhUserGuide files + +HTMLDOC = "/home/phoebus/ANJ/bin/htmldoc" +WEBSITE = /net/epics/Public/epics/EpicsDocumentation/ExtensionsManuals/AlarmHandler + +VERSION = 1.2.16 + +# Content options: + +BOOK = --book +TITLE = --title --titlefile ALH.title.html +TOC = --toclevels 3 +#LOGO = --logoimage alh.gif +TEXT = --bodyfont Times --fontsize 11.0 --fontspacing 1.2 +HDTEXT = --headingfont Times +#HDTEXT = --headingfont Helvetica +BODY = --textcolor black + +# .ps & .pdf options: + +PAGE = --duplex --size Universal --portrait --color +MARGINS = --left 1.0in --right 0.5in --top 0.5in --bottom 0.5in +HEADER = --header .t. --tocheader .t. +FOOTER = --footer c.1 --tocfooter ..i +HFTEXT = --headfootfont Times --headfootsize 11.0 + +OPTS = $(BOOK) $(TITLE) $(TOC) $(LOGO) $(TEXT) $(HDTEXT) $(BODY) +PAGEOPTS = $(OPTS) $(PAGE) $(MARGINS) $(HEADER) $(FOOTER) $(HFTEXT) + +PSOPTS = -t ps $(PAGEOPTS) +PDFOPTS = -t pdf --firstpage c1 $(PAGEOPTS) +HTMLOPTS = -t html $(OPTS) + + +FILES = ALH.html + + +# ALHUserGuide.html is name of file in alh/Makefile.Host + +all: alhUserGuide.ps.gz alhUserGuide.pdf ALHUserGuide.html + +alhUserGuide.ps: $(FILES) Makefile + $(HTMLDOC) $(PSOPTS) -f $@ $(FILES) + +alhUserGuide.pdf: $(FILES) Makefile + $(HTMLDOC) $(PDFOPTS) -f $@ $(FILES) + +ALHUserGuide.html: $(FILES) Makefile + rm -rf $@ + $(HTMLDOC) $(HTMLOPTS) -f $@ $(FILES) + +%.gz: % + rm -f $@ + gzip $< + +install: all + /bin/cp -f alhUserGuide.ps.gz $(WEBSITE)/alhUserGuide-$(VERSION).ps.gz + /bin/cp -f alhUserGuide.pdf $(WEBSITE)/alhUserGuide-$(VERSION).pdf + #/bin/cp -rf alhUserGuide $(WEBSITE)/alhUserGuide-$(VERSION) + rm -rf $(WEBSITE)/alhUserGuide-$(VERSION) + mkdir $(WEBSITE)/alhUserGuide-$(VERSION) + /bin/cp -rf . $(WEBSITE)/alhUserGuide-$(VERSION) + +clean: + rm alhUserGuide.ps alhUserGuide.pdf ALHUserGuide.html \ + alhUserGuide.ps.gz alhUserGuide.pdf.gz diff --git a/documentation/images/ALH.Large.gif b/documentation/images/ALH.Large.gif new file mode 100644 index 0000000..02cb0e7 Binary files /dev/null and b/documentation/images/ALH.Large.gif differ diff --git a/documentation/images/alhActionMenu.gif b/documentation/images/alhActionMenu.gif new file mode 100644 index 0000000..26de49c Binary files /dev/null and b/documentation/images/alhActionMenu.gif differ diff --git a/documentation/images/alhAlarmLogFile.gif b/documentation/images/alhAlarmLogFile.gif new file mode 100644 index 0000000..131b984 Binary files /dev/null and b/documentation/images/alhAlarmLogFile.gif differ diff --git a/documentation/images/alhBeepSeverity.gif b/documentation/images/alhBeepSeverity.gif new file mode 100644 index 0000000..4e48707 Binary files /dev/null and b/documentation/images/alhBeepSeverity.gif differ diff --git a/documentation/images/alhBrowserAlarmLog.gif b/documentation/images/alhBrowserAlarmLog.gif new file mode 100644 index 0000000..dd4bbee Binary files /dev/null and b/documentation/images/alhBrowserAlarmLog.gif differ diff --git a/documentation/images/alhBrowserOpMod.gif b/documentation/images/alhBrowserOpMod.gif new file mode 100644 index 0000000..a978f75 Binary files /dev/null and b/documentation/images/alhBrowserOpMod.gif differ diff --git a/documentation/images/alhConfigurationFile.gif b/documentation/images/alhConfigurationFile.gif new file mode 100644 index 0000000..150fc31 Binary files /dev/null and b/documentation/images/alhConfigurationFile.gif differ diff --git a/documentation/images/alhCurrentAlarmHistory.gif b/documentation/images/alhCurrentAlarmHistory.gif new file mode 100644 index 0000000..e4f6498 Binary files /dev/null and b/documentation/images/alhCurrentAlarmHistory.gif differ diff --git a/documentation/images/alhExitDialog.gif b/documentation/images/alhExitDialog.gif new file mode 100644 index 0000000..591907b Binary files /dev/null and b/documentation/images/alhExitDialog.gif differ diff --git a/documentation/images/alhFileMenu.gif b/documentation/images/alhFileMenu.gif new file mode 100644 index 0000000..3d3dfc0 Binary files /dev/null and b/documentation/images/alhFileMenu.gif differ diff --git a/documentation/images/alhForceMask.gif b/documentation/images/alhForceMask.gif new file mode 100644 index 0000000..89284c7 Binary files /dev/null and b/documentation/images/alhForceMask.gif differ diff --git a/documentation/images/alhForcePVDialog.gif b/documentation/images/alhForcePVDialog.gif new file mode 100644 index 0000000..7d4364b Binary files /dev/null and b/documentation/images/alhForcePVDialog.gif differ diff --git a/documentation/images/alhGuidance.gif b/documentation/images/alhGuidance.gif new file mode 100644 index 0000000..c8c6668 Binary files /dev/null and b/documentation/images/alhGuidance.gif differ diff --git a/documentation/images/alhMainWindowAlarms.gif b/documentation/images/alhMainWindowAlarms.gif new file mode 100644 index 0000000..f77aab8 Binary files /dev/null and b/documentation/images/alhMainWindowAlarms.gif differ diff --git a/documentation/images/alhMainWindowNoAlarms.gif b/documentation/images/alhMainWindowNoAlarms.gif new file mode 100644 index 0000000..9a90dce Binary files /dev/null and b/documentation/images/alhMainWindowNoAlarms.gif differ diff --git a/documentation/images/alhMessage.gif b/documentation/images/alhMessage.gif new file mode 100644 index 0000000..ca4d242 Binary files /dev/null and b/documentation/images/alhMessage.gif differ diff --git a/documentation/images/alhModifyMaskDialog.gif b/documentation/images/alhModifyMaskDialog.gif new file mode 100644 index 0000000..eb565dd Binary files /dev/null and b/documentation/images/alhModifyMaskDialog.gif differ diff --git a/documentation/images/alhModifyNoAckMaskPopup.gif b/documentation/images/alhModifyNoAckMaskPopup.gif new file mode 100644 index 0000000..fc707dc Binary files /dev/null and b/documentation/images/alhModifyNoAckMaskPopup.gif differ diff --git a/documentation/images/alhMotifMenu.gif b/documentation/images/alhMotifMenu.gif new file mode 100644 index 0000000..30ffaba Binary files /dev/null and b/documentation/images/alhMotifMenu.gif differ diff --git a/documentation/images/alhOpenFileDialog.gif b/documentation/images/alhOpenFileDialog.gif new file mode 100644 index 0000000..65ffb14 Binary files /dev/null and b/documentation/images/alhOpenFileDialog.gif differ diff --git a/documentation/images/alhOperModFile.gif b/documentation/images/alhOperModFile.gif new file mode 100644 index 0000000..b5b4c89 Binary files /dev/null and b/documentation/images/alhOperModFile.gif differ diff --git a/documentation/images/alhProperties.gif b/documentation/images/alhProperties.gif new file mode 100644 index 0000000..b0e8a20 Binary files /dev/null and b/documentation/images/alhProperties.gif differ diff --git a/documentation/images/alhRunWindow.gif b/documentation/images/alhRunWindow.gif new file mode 100644 index 0000000..160eae3 Binary files /dev/null and b/documentation/images/alhRunWindow.gif differ diff --git a/documentation/images/alhSaveFileDialog.gif b/documentation/images/alhSaveFileDialog.gif new file mode 100644 index 0000000..04537fe Binary files /dev/null and b/documentation/images/alhSaveFileDialog.gif differ diff --git a/documentation/images/alhSendMessage.gif b/documentation/images/alhSendMessage.gif new file mode 100644 index 0000000..0873118 Binary files /dev/null and b/documentation/images/alhSendMessage.gif differ diff --git a/documentation/images/alhSetBeepSeverityPopup.gif b/documentation/images/alhSetBeepSeverityPopup.gif new file mode 100644 index 0000000..7c3eac7 Binary files /dev/null and b/documentation/images/alhSetBeepSeverityPopup.gif differ diff --git a/documentation/images/alhSetupMenu.gif b/documentation/images/alhSetupMenu.gif new file mode 100644 index 0000000..98b9808 Binary files /dev/null and b/documentation/images/alhSetupMenu.gif differ diff --git a/documentation/images/alhViewMenu.gif b/documentation/images/alhViewMenu.gif new file mode 100644 index 0000000..67c4dc5 Binary files /dev/null and b/documentation/images/alhViewMenu.gif differ diff --git a/documentation/index.html b/documentation/index.html new file mode 100644 index 0000000..34fa683 --- /dev/null +++ b/documentation/index.html @@ -0,0 +1,7 @@ +<!doctype html> +<HTML> +<CENTER> +<A HREF="alhUserGuide.html"><IMG SRC="images/ALH.Large.gif" BORDER="0" WIDTH="160" HEIGHT="160"> +<H1>Alarm Handler User's Guide</H1></A> +</CENTER> +</html> diff --git a/fallback.h b/fallback.h new file mode 100644 index 0000000..af1120d --- /dev/null +++ b/fallback.h @@ -0,0 +1,59 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* fallback.h */ + +/************************DESCRIPTION*********************************** + alh fallback resource values +**********************************************************************/ + +#ifndef INCfallbackh +#define INCfallbackh 1 + +/* pushButtonName font needs to have 12 as height */ + +static String fallbackResources[] = { + "*initialResourcesPersistent: False", + "*nameTextW.background: green", + "*alh*foreground: black", + "*alh*background: #b0c3ca", + "*act*foreground: black", + "*act*background: #b0c3ca", + "*productDescriptionShell*background: #b0c3ca", + "*form_main.width: 1000", + "*form_main.height: 600", + "*form_main.x: 100", + "*form_main.x: 200", + "*drawing_area.width: 1000", + "*scale.value: 50", + "*scale.highlightOnEnter: FALSE", + "*scale.scaleMultiple: 5", + "*treeSym.fontList: 12x24", + "*XmCascadeButtonGadget.fontList: 8x13", + "*XmCascadeButtonWidget.fontList: 8x13", + "*XmPushButtonGadget.fontList: 8x13", + "*XmPushButtonWidget.fontList: 8x13", + "*XmToggleButtonGadget.fontList: 8x13", + "*XmToggleButtonWidget.fontList: 8x13", + "*ack.fontList: 7x14", + "*sevr.fontList: 7x14", + "*pushButtonName.fontList: -*-Helvetica-bold-r-*--12-*", + "*pushButtonGroupName.fontList: -*-Helvetica-bold-r-*--12-*", + "*warningMessage*background: Red", + "*warningMessage*foreground: White", + (String)NULL +}; + +#endif /* INCfallbackh */ + diff --git a/file.c b/file.c new file mode 100644 index 0000000..d117538 --- /dev/null +++ b/file.c @@ -0,0 +1,1300 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* file.c */ + +/************************DESCRIPTION*********************************** + File contains file handling routines +**********************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <errno.h> +#include "alh.h" + +#ifdef HAVE_SYSV_IPC +#include <sys/msg.h> +#endif + +#ifndef WIN32 +/* WIN32 does not have dirent.h used by opendir, closedir */ +#include <sys/stat.h> +#include <pwd.h> +#include <unistd.h> +#include <dirent.h> +#include <fcntl.h> +#else +#include <process.h> +#endif +#include <ctype.h> + +#include <Xm/Xm.h> + +#include "version.h" +#include "alLib.h" +#include "axArea.h" +#include "ax.h" + +/* global variables */ +char *programName; +int programId; + +/* default file names */ +#define DEFAULT_CONFIG "ALH-default.alhConfig" +#define DEFAULT_ALARM "ALH-default.alhAlarm" +#define DEFAULT_OPMOD "ALH-default.alhOpmod" + +extern ALINK *alhArea; /* need to group reload in MB-mode*/ + + +struct UserInfo { +char *loginid; +char *real_world_name; +char *myhostname; +char *displayName; +}; + +struct UserInfo userID; + +int _no_error_popup=0; /* No popup window. Error messages logged to opMod file. */ + +int _global_flag=0; /* Global execution mode. */ +int _transients_flag=0; /* Do ca_put of config file value for ackt */ + +int _main_window_flag=0; /* Flag: Start with main window */ + /* Default display filter function */ +int (*default_display_filter)(GCLINK *) = alFilterAll; + +int _read_only_flag=0; /* Read-only flag. Albert */ +int _passive_flag=0; /* Passive flag. Albert */ + +int _description_field_flag=0;/* Add description into the Log file */ +int _printer_flag=0; /* Printer flag. Albert */ +int printerMsgQKey; /* Network printer MsgQKey. Albert */ +int printerMsgQId; /* Network printer MsgQId. Albert */ + +int _time_flag=0; /* Dated flag. Albert */ + +int tm_day_old; /* Day-variable for dated. Albert */ + +int _DB_call_flag=0; /* Database(Oracle...) call. Albert */ +int DBMsgQKey; /* Database MsgQKey. Albert */ +int DBMsgQId; /* Database MsgQId. Albert */ + +int _message_broadcast_flag=0; /* MessBroadcast Sys Albert */ +char messBroadcastLockFileName[250]; /* FN for lock file. Albert */ +char messBroadcastInfoFileName[250]; /* FN for info file. Albert */ +int messBroadcastDeskriptor; /* FD for lock file. Albert */ +void broadcastMessTesting(); +XtIntervalId broadcastMessTimeoutId=0; +int amIsender=0; +int notsave=0; +const char *rebootString="MIN ALH WILL NOT SAVE ALARM LOG!!!!"; +char * reloadMBString = "0 RELOAD_FACILITY: "; +int max_not_save_time=10; +void broadcastMess_exit_quit(int); +unsigned long broadcastMessDelay=2000; /*(msec) periodic mess testing. Albert */ + +int _lock_flag=0; /* Flag for locking. Albert */ +char lockFileName[250]; /* FN for lock file. Albert */ +int lockFileDeskriptor; /* FD for lock file. Albert */ +unsigned long lockDelay=1000; /* (msec) periodical masterStatus testing. */ +int masterFlag=1; /* am I master for write operations? Albert */ +void masterTesting(); /* periodical calback of masterStatus testing*/ +extern Widget blinkToplevel; /* for locking status marking */ +char masterStr[64],slaveStr[64]; /* titles of Master/Slave +- printer/database*/ +XtIntervalId lockTimeoutId=0; +extern XFontStruct *font_info; +extern char alhVersionString[100]; + +#ifdef CMLOG + /* CMLOG flags & variables */ +int use_CMLOG_alarm = 0; +int use_CMLOG_opmod = 0; +#endif + +int _xml_flag = 0; /* Use XML-ish log format. SNS */ + +extern int DEBUG; + +extern int alarmLogFileMaxRecords; /* alarm log file maximum # records */ +extern int alarmLogFileOffsetBytes; /* alarm log file current offset in bytes */ + +extern FILE *fl; /* alarm log pointer */ +extern FILE *fo; /* opmod log pointer */ + +struct command_line_data +{ + char* configDir; + char* logDir; + char* configFile; + char* logFile; + char* opModFile; + int alarmLogFileMaxRecords; +}; +static struct command_line_data commandLine = { + NULL,NULL,NULL,NULL,NULL,0}; + +#define PARM_DEBUG 0 +#define PARM_ACT 1 +#define PARM_ALL_FILES_DIR 2 +#define PARM_LOG_DIR 3 +#define PARM_ALARM_LOG_FILE 4 +#define PARM_OPMOD_LOG_FILE 5 +#define PARM_ALARM_LOG_MAX 6 +#define PARM_DATABASE 7 +#define PARM_PRINTER 8 +#define PARM_DATED 9 +#define PARM_PASSIVE 10 +#define PARM_READONLY 11 +#define PARM_MESSAGE_BROADCAST 12 +#define PARM_SILENT 13 +#define PARM_LOCK 14 +#define PARM_HELP 15 +#define PARM_ALARM_LOG_CMLOG 16 +#define PARM_OPMOD_LOG_CMLOG 17 +#define PARM_GLOBAL 18 +#define PARM_CAPUT_ACK_TRANSIENTS 19 +#define PARM_VERSION 20 +#define PARM_NO_ERROR_POPUP 21 +#define PARM_MAIN_WINDOW 22 +#define PARM_ALARM_FILTER 23 +#define PARM_DESC_FIELD 24 +#define PARM_XML 25 +struct parm_data +{ + char* parm; + int len; + int id; +}; + +/* order of elements matters: long before short to prevent ambiguity */ + +static struct parm_data ptable[] = { +#ifdef CMLOG + { "-aCM", 4, PARM_ALARM_LOG_CMLOG }, +#endif + { "-a", 2, PARM_ALARM_LOG_FILE }, + { "-B", 2, PARM_MESSAGE_BROADCAST }, /* Albert */ + { "-c", 2, PARM_ACT }, + { "-caputackt", 10, PARM_CAPUT_ACK_TRANSIENTS }, + { "-D", 2, PARM_READONLY }, + { "-debug", 6 , PARM_DEBUG }, + { "-desc_field", 11 , PARM_DESC_FIELD }, + { "-filter", 7, PARM_ALARM_FILTER }, + { "-f", 2, PARM_ALL_FILES_DIR }, + { "-global", 7, PARM_GLOBAL }, + { "-help", 5, PARM_HELP }, + { "-L", 2, PARM_LOCK }, /* Albert */ + { "-l", 2, PARM_LOG_DIR }, + { "-mainwindow", 11, PARM_MAIN_WINDOW }, + { "-m", 2, PARM_ALARM_LOG_MAX }, + { "-noerrorpopup", 13, PARM_NO_ERROR_POPUP }, + { "-O", 2, PARM_DATABASE }, /* Albert */ +#ifdef CMLOG + { "-oCM", 4, PARM_OPMOD_LOG_CMLOG }, +#endif + { "-o", 2, PARM_OPMOD_LOG_FILE }, + { "-P", 2, PARM_PRINTER }, + { "-S", 2, PARM_PASSIVE }, + { "-s", 2, PARM_SILENT }, + { "-T", 2, PARM_DATED }, + { "-v", 2, PARM_VERSION }, + { "-version", 8, PARM_VERSION }, + { "-xml", 4, PARM_XML }, /* SNS */ + { NULL, -1, -1 }}; + +/* forward declarations */ +static void saveConfigFile_callback(Widget widget,char *filename, +XmAnyCallbackStruct *cbs); +static void printUsage(char *); +static void fileSetup(char *filename,ALINK *area,int fileType,int programId, +Widget widget); +static int checkFilename(char *filename,int fileType); +static int getCommandLineParms(int argc, char** argv); +int getUserInfo(); + +/*************************************************** + exit and quit application +***************************************************/ +void exit_quit(Widget w, XtPointer clientdata, XtPointer calldata) +{ + struct subWindow *subWindow; + ALINK *area = (ALINK *)clientdata; + GLINK *proot=0; + if(_message_broadcast_flag && amIsender) { + createDialog(blinkToplevel,XmDIALOG_MESSAGE, + "You sent a message\n","Wait a seconds before message will delivery\n"); + return; + } + + alLogOpModMessage(0,0,"Setup---Exit"); + fclose(fl); + fclose(fo); + if (area && area->pmainGroup) proot = area->pmainGroup->p1stgroup; + + /* + * note: if pmainGroup or proot == NULL then probably never even fired up initial + * configuration file and ca... + */ + if (proot) { + + /* cancel all the channel access requests */ + if (programId==ALH) { + alCaCancel(area->pmainGroup); + alCaStop(); + } + + /* delete all the subgroups of proot & free proot */ + alDeleteGroup(proot); + + } + + if (programId==ACT) editClipboardSet(0,0); + if (area){ + if (area->treeWindow){ + subWindow=area->treeWindow; + if (subWindow->lines) free(subWindow->lines); + free(area->treeWindow); + } + if (area->groupWindow){ + subWindow=area->groupWindow; + if (subWindow->lines) free(subWindow->lines); + free(area->groupWindow); + } + if (area->propWindow) free(area->propWindow); + if (area->forceMaskWindow) free(area->forceMaskWindow); + if (area->forcePVWindow) free(area->forcePVWindow); + if (area->maskWindow) free(area->maskWindow); + if (area->beepSevrWindow) free(area->beepSevrWindow); + if (area->noAckWindow) free(area->noAckWindow); + alHeartbeatPVRemove(area->pmainGroup); + if (area->pmainGroup) free(area->pmainGroup); + free(area); + } + XtDestroyWidget(topLevelShell); + XFreeFont(display,font_info); +#ifndef WIN32 + if(_lock_flag) { + lockf(lockFileDeskriptor,F_ULOCK, 0L); /* Albert */ + if (lockTimeoutId) { + XtRemoveTimeOut(lockTimeoutId); + } + if(_message_broadcast_flag) { + lockf(messBroadcastDeskriptor, F_ULOCK, 0L); /* Albert */ + if (broadcastMessTimeoutId) { + XtRemoveTimeOut(broadcastMessTimeoutId); + } + } + + } +#endif + +#ifdef CMLOG + if (use_CMLOG_alarm || use_CMLOG_opmod) alCMLOGdisconnect(); +#endif + + exit(0); +} + +/****************************************************** + shorten file name without path +******************************************************/ +char *shortfile(char *name) +{ + int len; + char *shortname; + + len = strlen(name); + shortname = name; + while (len != 0) { + if(*(name+len)== '/') { + shortname = name+len+1; + break; + } + len--; + } + return shortname; +} + +/****************************************************** + checkFilename +******************************************************/ +static int checkFilename(char *filename,int fileType) +{ + FILE *tt = 0; + + if ( filename[0] == '\0') return 2; + + if ( DEBUG == 1 ) + printf("\nFilename is %s \n", filename); + + switch (fileType) { + case FILE_CONFIG: + case FILE_CONFIG_INSERT: + tt = fopen(filename,"r"); + if (!tt){ + return 2; + } + break; + + case FILE_SAVEAS: + tt = fopen(filename,"r"); + if (tt){ + return 3; + } + + case FILE_SAVE: + case FILE_SAVEAS_OK: + case FILE_PRINT: + tt = fopen(filename,"w"); + if (!tt){ + return 4; + } + break; + + case FILE_OPMOD: + case FILE_ALARMLOG: + if(!_read_only_flag) tt = fopen(filename,"a"); + else { + tt = fopen(filename,"r"); + if(!tt) + { + strcpy(filename,"/tmp/AlhDisableWriting"); + chmod("/tmp/AlhDisableWriting",0777); + tt = fopen(filename,"w"); + if (!tt) { + fprintf(stderr,"can't read OPMOD or ALARMLOG and /tmp directory \n"); + exit(1); + } + } + } + if (!tt){ + return 4; + } + break; + } + + fclose(tt); + return 0; +} + +/****************************************************** + fileCancelCallback +******************************************************/ +void fileCancelCallback(Widget widget,ALINK *area, +XmFileSelectionBoxCallbackStruct *cbs) +{ + area->managed = TRUE; + XtUnmanageChild(widget); +} + +/****************************************************** + fileSetupCallback +******************************************************/ +void fileSetupCallback(Widget widget,int client_data, +XmFileSelectionBoxCallbackStruct *cbs) +{ + char *filename; + ALINK *area; + int pgm; + + + /* get the filename string */ + XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &filename); + + if ( DEBUG == 1 ) + printf("\nfileSetupCallback: filename is %s \n", filename); + + /* get the area pointer */ + XtVaGetValues(widget, XmNuserData, &area, NULL); + + if (area) pgm = area->programId; + else pgm = programId; + fileSetup(filename,area,client_data,pgm,widget); + XtFree(filename); + +} + +/****************************************************** + fileSetup +******************************************************/ +static void fileSetup(char *filename,ALINK *area,int fileType, +int programId,Widget widget) +{ + int error; + char fileTypeString[NAMEDEFAULT_SIZE]; + char str[MAX_STRING_LENGTH]; + char *dir=0; + char *pattern=0; + char *filename_dup; + FILE *tt; + Widget fileSelectionBox; + time_t timeofday; + struct tm *tms; + char buf[16]; + + /* _______ For Dated AlLog File. Albert______________________________*/ + timeofday = time(0L); + tms = localtime(&timeofday); + sprintf(buf,".%.4d-%.2d-%.2d", + 1900+tms->tm_year,1+tms->tm_mon,tms->tm_mday); + buf[11]=0; + tm_day_old = tms->tm_mday; + if ( ((fileType == FILE_ALARMLOG)||(fileType == FILE_OPMOD))&&(_time_flag) ) + { + strncat(filename, &buf[0], strlen(buf)); + } + /* _______ End. Albert______________________________*/ + error = checkFilename(filename,fileType); + if (error){ + switch(fileType) { + + case FILE_CONFIG: + case FILE_CONFIG_INSERT: + pattern = CONFIG_PATTERN; + dir = psetup.configDir; + if (programId == ALH) { + strcpy(fileTypeString,"Alarm Handler: Alarm Configuration File"); + } else { + /* not error to start act with no filename */ + if ( filename[0] == '\0' && fileType == FILE_CONFIG ) error = 0; + strcpy(fileTypeString,"Alarm Configuration Tool: Alarm Configuration File"); + } + break; + + case FILE_OPMOD: + pattern = OPMOD_PATTERN; + dir = psetup.logDir; + strcpy(fileTypeString,"OpMod Log File"); + break; + + case FILE_ALARMLOG: + pattern = ALARMLOG_PATTERN; + dir = psetup.logDir; + strcpy(fileTypeString,"Alarm Log File"); + break; + + case FILE_PRINT: + pattern = TREEREPORT_PATTERN; + dir = NULL; + strcpy(fileTypeString,"Print File"); + break; + + default: + pattern = '\0'; + dir = psetup.configDir; + strcpy(fileTypeString,"Filename"); + break; + + } + + } + if (error){ + fileSelectionBox = widget; + /* Display file selection box */ + if ( XtIsShell(widget)) { + long fileTypeLong=fileType; + fileSelectionBox = createFileDialog(widget, + (void *)fileSetupCallback, (XtPointer)fileTypeLong, + (void *)exit_quit,(XtPointer)FALSE, + (XtPointer)NULL, + fileTypeString, (String)pattern, dir); + } + + /* Display file error dialog */ + switch (error){ + case 1: + createDialog(fileSelectionBox,XmDIALOG_ERROR,filename," is a directory."); + break; + + case 2: + /* no warning if DEFAULT filename does not exist */ + if ( strcmp(shortfile(filename),DEFAULT_CONFIG) ) + createDialog(fileSelectionBox,XmDIALOG_ERROR,filename," open error."); + break; + + case 3: + strcpy(str, filename); + strcat(str," already exists. Overwrite?"); + filename_dup = malloc(strlen(filename)+1); + if ( filename_dup ) strcpy(filename_dup,filename); + createActionDialog(fileSelectionBox,XmDIALOG_WARNING, str , + (XtCallbackProc)saveConfigFile_callback, + (XtPointer)filename_dup,(XtPointer)area); + break; + + case 4: + /*createDialog(fileSelectionBox,XmDIALOG_ERROR,filename," write error.");*/ + fatalErrMsg("Write error for file %s.\n",filename); + break; + default: + break; + } + } else { + /* unmanage the fileSelection dialog */ + if ( !XtIsShell(widget)) + createFileDialog(0,0,0,0,0,0,0,0,0); + + switch(fileType) { + + case FILE_CONFIG: +#ifdef CMLOG + if (use_CMLOG_alarm || use_CMLOG_opmod) alCMLOGconnect(); +#endif + + setupConfig(filename,programId,area); + if(_lock_flag) /* Albert */ + { + FILE *fp; + strcpy(lockFileName,psetup.configFile); + strcat(lockFileName,".LOCK"); + if (!(fp=fopen(lockFileName,"a"))) + { + perror("Can't open locking file for a"); + exit(1); + } + fclose(fp); +#ifndef WIN32 + if((lockFileDeskriptor=open(lockFileName,O_RDWR,0644)) == 0) + { + perror("Can't open locking file for rw"); + exit(1); + } +#endif + if (DEBUG) fprintf(stderr,"INIT: deskriptor for %s=%d\n", + lockFileName,lockFileDeskriptor); + strcpy(masterStr,"Master"); + strcpy(slaveStr, "Slave"); + if(_printer_flag) { + strcat(masterStr,"+printer"); + strcat(slaveStr, "+printer"); + } + if(_DB_call_flag) { + strcat(masterStr,"+Oracle"); + strcat(slaveStr, "+Oracle"); + } + if(_message_broadcast_flag) { + strcat(masterStr,"+Message"); + strcat(slaveStr, "+Message"); + } + + masterTesting(); /* Albert */ + } + if(_message_broadcast_flag) /* Albert */ + { + FILE *fpL, *fpI; + strcpy(messBroadcastLockFileName,psetup.configFile); + strcat(messBroadcastLockFileName,".MESSLOCK"); + strcpy(messBroadcastInfoFileName,psetup.configFile); + strcat(messBroadcastInfoFileName,".MESS"); + if ( (!(fpL=fopen(messBroadcastLockFileName,"a"))) + || (!(fpI=fopen(messBroadcastInfoFileName,"a"))) ) + { + perror("Can't open messBroadcast file for a"); + exit(1); + } + fclose(fpL); + fclose(fpI); +#ifndef WIN32 + if((messBroadcastDeskriptor= + open(messBroadcastLockFileName,O_RDWR,0644)) == 0) + { + perror("Can't open messBroadcast file for rw"); + exit(1); + } +#endif + if (DEBUG) fprintf(stderr,"INIT: deskriptor for %s=%d\n", + messBroadcastLockFileName,messBroadcastDeskriptor); + broadcastMessTesting(widget); + signal(SIGINT,broadcastMess_exit_quit); + } + +#ifdef HAVE_SYSV_IPC + if( _printer_flag) + { + struct msqid_ds buf; + printerMsgQId = msgget (printerMsgQKey, 0600|IPC_CREAT); + if(printerMsgQId == -1) {perror("printer:msgQ_create"); exit(1);} + else { + if(DEBUG) fprintf(stderr,"printerMsgQ with key=%d is OK\n", + printerMsgQKey); + if (msgctl(printerMsgQId,IPC_STAT,&buf) != 1) + { + if(DEBUG)fprintf(stderr,"printer:o=%d.%d,perm=%04o,max byte=%ld\n", + buf.msg_perm.uid,buf.msg_perm.gid, + buf.msg_perm.mode, + buf.msg_qbytes); + if(DEBUG) fprintf(stderr,"printer:%ld msgs = %ld bytes on queue\n", + buf.msg_qnum, buf.msg_cbytes); + } + else {perror("printer:msgctl()"); exit(1);} + } + } + if( _DB_call_flag) + { + struct msqid_ds buf; + DBMsgQId = msgget (DBMsgQKey, 0600|IPC_CREAT); + if(DBMsgQId == -1) {perror("DB:msgQ_create"); exit(1);} + else { + if(DEBUG) fprintf(stderr,"DB:msgQ with key=%d is OK\n", + DBMsgQKey); + if (msgctl(DBMsgQId,IPC_STAT,&buf) != 1) + { + if(DEBUG)fprintf(stderr,"DB:o=%d.%d,perm=%04o,max byte=%ld\n", + buf.msg_perm.uid,buf.msg_perm.gid, + buf.msg_perm.mode, + buf.msg_qbytes); + if(DEBUG) fprintf(stderr,"DB:%ld msgs = %ld bytes on queue\n", + buf.msg_qnum, buf.msg_cbytes); + } + else {perror("DB:msgctl()"); exit(1);} + } + } + +#endif + break; + + case FILE_ALARMLOG: + if (fo) alLogOpModMessage(0,0,"Setup Alarm Log File : %s",filename); + strcpy(psetup.logFile,filename); + if (fl) fclose(fl); /* RO-flag. Albert */ + if(_read_only_flag) fl = fopen(psetup.logFile,"r"); + else if((_time_flag)||(_lock_flag)) fl = fopen(psetup.logFile,"a"); + else fl = fopen(psetup.logFile,"w+"); + if (!fl) perror("CAN'T OPEN LOG FILE"); /* Albert */ + if (alarmLogFileMaxRecords) alarmLogFileOffsetBytes = 0; + break; + + case FILE_OPMOD: + if (fo) alLogOpModMessage(0,0,"Setup OpMod File : %s",filename); + strcpy(psetup.opModFile,filename); + if (fo) fclose(fo); + if(!_read_only_flag) fo=fopen(psetup.opModFile,"a"); + /* RO-option. Albert */ + else fo=fopen(psetup.opModFile,"r"); + if (!fo) perror("CAN'T OPEN OP FILE"); /* Albert */ + break; + + case FILE_SAVEAS: + case FILE_SAVE: + filename_dup = malloc(strlen(filename)+1); + if ( filename_dup ) strcpy(filename_dup,filename); + saveConfigFile_callback(widget,filename_dup,(void *)NULL); + break; + + case FILE_PRINT: + tt = fopen(filename,"w"); + alPrintConfig(tt,area->pmainGroup); + fclose(tt); + break; + + case FILE_CONFIG_INSERT: + editInsertFile(filename,area); + break; + } + } +} + +/****************************************************** + saveConfigFile_callback +******************************************************/ +static void saveConfigFile_callback(Widget widget,char *filename, +XmAnyCallbackStruct *cbs) +{ + ALINK *area; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + if (fo) alLogOpModMessage(0,0,"Setup Save New Config: %s",filename); + + if ( DEBUG == 1 ) + printf("\nSaving Config File to %s \n", filename); + + alWriteConfig(filename,area->pmainGroup); + /* unmanage the warning dialog */ + XtUnmanageChild(widget); + /* unmanage the fileSelection dialog */ + createFileDialog(0,0,0,0,0,0,0,0,0); + /* Free the filename string copy */ + free(filename); +} + +/****************************************************** + getCommandLineParms +******************************************************/ +static int getCommandLineParms(int argc, char** argv) +{ + int i,j; + int finished=0; + int parm_error=0; + + alarmLogFileMaxRecords=commandLine.alarmLogFileMaxRecords=2000; /* Albert */ + + for(i=1;i<argc && !parm_error;i++) + { + for(j=0;!finished && !parm_error && ptable[j].parm;j++) + { + if(strncmp(ptable[j].parm,argv[i],Mmax(ptable[j].len,strlen(argv[i])))==0) + { + switch(ptable[j].id) + { + + case PARM_DEBUG: + DEBUG = TRUE; + finished=1; + break; + case PARM_ACT: + strcpy(programName,"act"); + programId = ACT; + finished=1; + break; + case PARM_SILENT: + psetup.silenceForever=TRUE; + finished=1; + break; + case PARM_ALL_FILES_DIR: + if(++i>=argc) parm_error=1; + else + { + if(argv[i][0]=='-') parm_error=2; + else + { + commandLine.configDir=argv[i]; + finished=1; + } + } + break; + case PARM_LOG_DIR: + if(++i>=argc) parm_error=1; + else + { + if(argv[i][0]=='-') parm_error=2; + else + { + commandLine.logDir=argv[i]; + finished=1; + } + } + break; + case PARM_ALARM_LOG_FILE: + if(++i>=argc) parm_error=1; + else + { + if(argv[i][0]=='-') parm_error=2; + else + { + commandLine.logFile=argv[i]; + finished=1; + } + } + break; + case PARM_OPMOD_LOG_FILE: + if(++i>=argc) parm_error=1; + else + { + if(argv[i][0]=='-') parm_error=2; + else + { + commandLine.opModFile=argv[i]; + finished=1; + } + } + break; + case PARM_ALARM_FILTER: + if(++i>=argc) parm_error=1; + else + { + if (argv[i][0] == 'a') { + default_display_filter = alFilterAlarmsOnly; + finished = 1; + } else if (argv[i][0] == 'u') { + default_display_filter = alFilterUnackAlarmsOnly; + finished = 1; + } else if (argv[i][0] == 'n') { + default_display_filter = alFilterAll; + finished = 1; + } else parm_error=2; + } + break; +#ifdef CMLOG + case PARM_ALARM_LOG_CMLOG: + use_CMLOG_alarm = 1; + finished=1; + break; + case PARM_OPMOD_LOG_CMLOG: + use_CMLOG_opmod = 1; + finished=1; + break; +#endif + case PARM_ALARM_LOG_MAX: + if(++i>=argc) parm_error=1; + else + { + if(argv[i][0]=='-') parm_error=2; + else + { + commandLine.alarmLogFileMaxRecords=atoi(argv[i]); + if( (!commandLine.alarmLogFileMaxRecords)&&(strcmp(argv[i],"0") )) parm_error=2; + alarmLogFileMaxRecords=commandLine.alarmLogFileMaxRecords; + finished=1; + } + } + break; + case PARM_PRINTER: /* Printer parameters. Albert */ + if(++i>=argc) parm_error=1; + else + { + if(argv[i][0]=='-') parm_error=2; + else + { + printerMsgQKey=atoi(argv[i]); + if(!printerMsgQKey) parm_error=2; + _printer_flag=1; + finished=1; + } + } + break; + case PARM_DATED: + _time_flag=1; /* Dated-option. Albert */ + finished=1; + break; + case PARM_PASSIVE: + /*_read_only_flag=1;*/ /* Passive-option. Albert */ + _passive_flag=1; + finished=1; + break; + case PARM_READONLY: + _read_only_flag=1; /* RO-option. Albert */ + finished=1; + break; + case PARM_LOCK: + _lock_flag=1; /* locking system. Albert */ + finished=1; + break; + case PARM_DATABASE: /* DATABASE-option. Albert */ + if(++i>=argc) parm_error=1; + else + { + if(argv[i][0]=='-') parm_error=2; + else + { + DBMsgQKey=atoi(argv[i]); + if(!DBMsgQKey) parm_error=2; + _DB_call_flag=1; + finished=1; + } + } + break; + case PARM_MESSAGE_BROADCAST: + _message_broadcast_flag=1;/* Mess. Broadcast Albert */ + finished=1; + break; + case PARM_MAIN_WINDOW: + _main_window_flag=1; + finished=1; + break; + case PARM_NO_ERROR_POPUP: + _no_error_popup=1; + finished=1; + break; + case PARM_GLOBAL: + _global_flag=1; + finished=1; + break; + case PARM_CAPUT_ACK_TRANSIENTS: + _transients_flag=1; + finished=1; + break; + case PARM_HELP: + printUsage(argv[0]); + finished=1; + break; + case PARM_VERSION: + fprintf(stderr,"%s\n",alhVersionString); + exit(1); + break; + case PARM_DESC_FIELD: + _description_field_flag=1; + finished=1; + break; + case PARM_XML: /* SNS */ + _xml_flag=1; + finished=1; + break; + default: + parm_error=1; + break; + } + } + } + if (!finished && !parm_error) + { + if(i+1==argc) + { + if(argv[i][0]=='-') parm_error=1; + else + { + commandLine.configFile=argv[i]; + finished=1; + } + } + else parm_error=1; + } else { + finished=0; + } + } + + if (_lock_flag) commandLine.alarmLogFileMaxRecords = 0; + +if(_printer_flag&&!_lock_flag) + { + fprintf(stderr,"use -P together with -L\n"); + parm_error=1; + } + +if(_DB_call_flag&&!_lock_flag) + { + fprintf(stderr,"use -O together with -L\n"); + parm_error=1; + } + + if (parm_error == 1) { + fprintf(stderr,"\nInvalid command line option %s\n ", argv[i-1]); + printUsage(argv[0]); + return 1; + } + if (parm_error == 2) { + fprintf(stderr,"\nInvalid command line option %s %s\n ", argv[i-2], argv[i-1]); + printUsage(argv[0]); + return 1; + } + + if (_xml_flag) puts ("XML!"); else puts("no XML!"); + + return 0; +} + +/****************************************************** + printUsage +******************************************************/ +static void printUsage(char *pgm) +{ + fprintf(stderr,"usage: %s [OPTIONS] [Xoptions] [configfile]\n", pgm); + fprintf(stderr,"where:\n"); + fprintf(stderr," configfile Alarm configuration filename ["DEFAULT_CONFIG"]\n"); + fprintf(stderr,"OPTIONS:\n"); + fprintf(stderr," -a alarmlogfile Alarm log filename ["DEFAULT_ALARM"]\n"); +#ifdef CMLOG + fprintf(stderr," -aCM Alarm log using CMLOG\n"); +#endif + fprintf(stderr," -B Message Broadcast System\n"); + fprintf(stderr," -c Alarm Configuration Tool mode\n"); + fprintf(stderr," -caputackt Caput config file ackt settings to channels on startup\n"); + fprintf(stderr," (if global and active)\n"); + fprintf(stderr," -D Disable alarm and opmod log writing\n"); + fprintf(stderr," -debug Debug output\n"); + fprintf(stderr," -desc_field Add record description to the LogFile\n"); + fprintf(stderr," -f filedir Directory for config files [.]\n"); + fprintf(stderr," -filter f-opt Set alarm display filter with f-opt being one of [no]\n"); + fprintf(stderr," n[o]: no filter\n"); + fprintf(stderr," a[ctive]: show only active alarms\n"); + fprintf(stderr," u[nack]: show only unacknowledged alarms\n"); + fprintf(stderr," -global Global mode (acks and ackt fields) \n"); + fprintf(stderr," -help Print usage\n"); + fprintf(stderr," -L Locking system\n"); + fprintf(stderr," -l logdir Directory for log files [.]\n"); + fprintf(stderr," -m maxrecords Alarm log file max records [2000]\n"); + fprintf(stderr," -mainwindow Start with main window\n"); + fprintf(stderr," -noerrorpopup Do not display error popup window (errors are logged).\n"); + fprintf(stderr," -O key Database call\n"); + fprintf(stderr," -o opmodlogfile OpMod log filename ["DEFAULT_OPMOD"]\n"); +#ifdef CMLOG + fprintf(stderr," -oCM OpMod log using CMLOG\n"); +#endif + fprintf(stderr," -P key Print to TCP printer\n"); + fprintf(stderr," -S Passive (no caputs - acks field, ackt field, sevrpv)\n"); + fprintf(stderr," -s Silent (no alarm beeping)\n"); + fprintf(stderr," -T AlarmLogDated\n"); + fprintf(stderr," -xml Use XML-ish format for log files\n"); /* SNS */ + fprintf(stderr," -v Print version number\n"); + fprintf(stderr," -version Print version number\n"); + exit(1); +} + +/****************************************************** + fileSetupInit +******************************************************/ +void fileSetupInit( widget, argc, argv) +Widget widget; +int argc; +char *argv[]; +{ + int len; + char configFile[NAMEDEFAULT_SIZE]; + char logFile[NAMEDEFAULT_SIZE]; + char opModFile[NAMEDEFAULT_SIZE]; + char *name = NULL; + programId = ALH; + programName = (char *)calloc(1,4); + strcpy(programName,"alh"); + + getUserInfo(); /*Get info (usr,Fullusr,host,displ) about operator Albert*/ + + /* get optional command line parameters */ + getCommandLineParms(argc,argv); + + if (DEBUG) printf("programName=%s\n",programName); + + if (commandLine.configDir) + psetup.configDir=commandLine.configDir; + else + psetup.configDir=getenv("ALARMHANDLER"); + + if (commandLine.logDir) + psetup.logDir=commandLine.logDir; + + if (psetup.configDir && !psetup.logDir) + psetup.logDir=psetup.configDir; + + /* ----- initialize and setup opMod file ----- */ + if (psetup.logDir) { + strncpy(psetup.opModFile,psetup.logDir,NAMEDEFAULT_SIZE-1); + strcat(psetup.opModFile,"/"); + } + if (commandLine.opModFile) { + strncpy(opModFile,commandLine.opModFile,NAMEDEFAULT_SIZE-1); + } else { + strcpy(opModFile,DEFAULT_OPMOD); + } + name = opModFile; + if ( name[0] == '/' || (name[0] == '.' && name[1] == '.') || + (name[0] == '.' && name[1] == '/')) { + strncpy(psetup.opModFile,opModFile,NAMEDEFAULT_SIZE); + } else { + len = strlen(psetup.opModFile); + strncat(psetup.opModFile,opModFile,NAMEDEFAULT_SIZE-len); + } + if (DEBUG == 1 ) printf("\nOpMod File is %s \n", psetup.opModFile); + fileSetup(psetup.opModFile,NULL,FILE_OPMOD,programId,widget); + + /* ----- initialize and setup alarm log file ----- */ + if (psetup.logDir) { + strncpy(psetup.logFile,psetup.logDir,NAMEDEFAULT_SIZE-1); + strcat(psetup.logFile,"/"); + } + if (commandLine.logFile) { + strncpy(logFile,commandLine.logFile,NAMEDEFAULT_SIZE-1); + } else { + strcpy(logFile,DEFAULT_ALARM); + } + name = logFile; + if ( name[0] == '/' || (name[0] == '.' && name[1] == '.') || + (name[0] == '.' && name[1] == '/')) { + strncpy(psetup.logFile,logFile,NAMEDEFAULT_SIZE); + } else { + len = strlen(psetup.logFile); + strncat(psetup.logFile,logFile,NAMEDEFAULT_SIZE-len); + } + if (DEBUG == 1 ) printf("\nAlarmLog File is %s \n", psetup.logFile); + fileSetup(psetup.logFile,NULL,FILE_ALARMLOG,programId,widget); + + /* ----- initialize and setup config file ----- */ + if (psetup.configDir) { + strncpy(psetup.configFile,psetup.configDir,NAMEDEFAULT_SIZE-1); + strcat(psetup.configFile,"/"); + } + if (commandLine.configFile) { + strncpy(configFile,commandLine.configFile,NAMEDEFAULT_SIZE-1); + } else { + if (programId == ALH) strcpy(configFile,DEFAULT_CONFIG); /*Albert */ + } + name = configFile; + if ( name[0] == '/' || (name[0] == '.' && name[1] == '.') || + (name[0] == '.' && name[1] == '/')) { + strncpy(psetup.configFile,configFile,NAMEDEFAULT_SIZE); + } else { + len = strlen(psetup.configFile); + strncat(psetup.configFile,configFile,NAMEDEFAULT_SIZE-len); + } + if (DEBUG == 1 ) printf("\nConfig File is %s \n", psetup.configFile); + fileSetup(psetup.configFile,NULL,FILE_CONFIG,programId,widget); + + +} +/* *******************************new code. Albert************************************* */ +void masterTesting() +{ +#ifndef WIN32 + if ( lockf(lockFileDeskriptor, F_TLOCK, 0L) < 0 ) { + if ((errno == EAGAIN || errno == EACCES )) { + masterFlag=0; + if(DEBUG) fprintf(stderr,"I'm slave;lockFileDeskriptor=%d\n",lockFileDeskriptor); + XtVaSetValues(blinkToplevel,XmNtitle,slaveStr,NULL); + } + else { + perror("lockf Error!!!!"); /* Albert exit ?????? */ + } + } + else + { + masterFlag=1; + if(DEBUG) fprintf(stderr,"I'm master;lockFileDeskriptor=%d\n",lockFileDeskriptor); + XtVaSetValues(blinkToplevel,XmNtitle,masterStr,NULL); + } + + lockTimeoutId = XtAppAddTimeOut(appContext, lockDelay,(XtTimerCallbackProc)masterTesting , NULL); + +#endif +} + +void broadcastMessTesting(Widget w) +{ +FILE *fp; +static char messID[30]; +char firstLine[30]; +char messBuff[500]; +char buff[250]; +char *blank; +int notsave_time; +void notsaveProc(); + +broadcastMessTimeoutId=XtAppAddTimeOut(appContext,broadcastMessDelay,(XtTimerCallbackProc)broadcastMessTesting,w); +if ( (fp=fopen(messBroadcastInfoFileName,"r")) == NULL ) + { + perror("broadcastMessTesting: can't open messBroadcastInfoFileName!!!!"); + return; + } +if (fgets(firstLine,32,fp)==NULL) {fclose(fp); return;} + +if(strcmp(firstLine,messID) == 0) {fclose(fp); return;} +strcpy(messID,firstLine); +memset(messBuff,0,250); +fgets (messBuff, 250, fp); /* Mess */ +fgets(buff,250,fp); +strcat(messBuff,buff); /* Date */ +fgets(buff,250,fp); +strcat(messBuff,buff); /* From */ +fclose(fp); + +if(!amIsender) + { + createDialog(w,XmDIALOG_INFORMATION,"\nBROADCAST MESSAGE:\n",messBuff); + XBell(XtDisplay(w),50); + } +if(strncmp(messBuff,reloadMBString+2,strlen(reloadMBString)-3 )==0) { + + ALINK *area=NULL; + + if(DEBUG) fprintf(stderr,"reload!\n"); + XtVaGetValues(blinkToplevel, XmNuserData, &area, NULL); + if (!area){ /* !ar */ + /*fprintf(stderr,"\nBad AREA\n");*/ + /* return;*/ + } + /* + if(DEBUG)printf("\nfileSetupCallback: \n"); + if(DEBUG)printf("\nfileSetupCallback: filename is %d \n", area->programId); + if(DEBUG)printf("\nfileSetupCallback: filename is %s \n", area->configFile); + */ + fileSetup(psetup.configFile,alhArea,FILE_CONFIG,ALH,w); + if(DEBUG) fprintf(stderr,"broadcastMessTestingEnd for reload\n"); + return; +} + +if ( (blank=strchr( (const char *) messBuff, ' ')) == NULL ) return; +if(strncmp(blank+1,rebootString,strlen(rebootString)-1 )==0) { + *blank=0; + notsave_time=atoi(messBuff); + if(DEBUG) fprintf(stderr,"notsave_time=%d\n",notsave_time); + if( (notsave_time <= 0) || (notsave_time > max_not_save_time) ) + { + createDialog(w,XmDIALOG_INFORMATION,"\nNot_save failed\n","time is so big"); + return; + } + alLogNotSaveStart(notsave_time); + + notsave=1; + XtAppAddTimeOut(appContext,notsave_time*1000*60 ,(XtTimerCallbackProc) notsaveProc, w); + +} +} + +void notsaveProc(Widget w) +{ +time_t time_tmp; +notsave=0; +time_tmp=time(0L); +alLogNotSaveFinish(); +createDialog(w,XmDIALOG_MESSAGE,ctime(&time_tmp),"We start save alarmLog again \n"); +} + +void broadcastMess_exit_quit(int unused) +{ +exit_quit(NULL,NULL,NULL); +/* signal(SIGINT,broadcastMess_exit_quit); Albert */ +} + +int getUserInfo() +{ +static char myhostname[256]; +static char loginid[16]; +static char real_world_name[128]; +static char displayName[256]; +int ret=0; + +#ifndef WIN32 +struct passwd *pp; +int effective_uid; + + effective_uid = geteuid(); + if ((pp = getpwuid(effective_uid))) + { + strcpy(loginid,pp->pw_name); + strcpy(real_world_name,pp->pw_gecos); + } + else + { + strcpy(loginid,"Unknoun_user"); + strcpy(real_world_name," "); + ret=1; + } + if(gethostname(myhostname,256) != 0) + { + strcpy(myhostname,"unknoun_host"); + ret=1; + } + if(display) strcpy(displayName,DisplayString(display)); + else + { + strcpy(displayName,"unknown_display"); + ret=1; + } + userID.loginid=loginid; + userID.real_world_name=real_world_name; + userID.myhostname=myhostname; + userID.displayName=displayName; +#endif + return(ret); +} + +/* *******************************End of new code. Albert ************************* */ + + + + + + + diff --git a/force.c b/force.c new file mode 100644 index 0000000..9734a1d --- /dev/null +++ b/force.c @@ -0,0 +1,1357 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* force.c */ + +/************************DESCRIPTION*********************************** + Routines for modifing the forcePV using a popup dialog window +**********************************************************************/ + +#include <stdlib.h> +#include <ctype.h> + +#include <Xm/Xm.h> +#include <Xm/AtomMgr.h> +#include <Xm/DialogS.h> +#include <Xm/Form.h> +#include <Xm/Frame.h> +#include <Xm/LabelG.h> +#include <Xm/PushB.h> +#include <Xm/ToggleB.h> +#include <Xm/PanedW.h> +#include <Xm/Protocols.h> +#include <Xm/RowColumn.h> +#include <Xm/ScrolledW.h> +#include <Xm/Text.h> +#include <Xm/TextF.h> +#include <Xm/ToggleBG.h> + +#include "postfix.h" +#include "axArea.h" +#include "alLib.h" +#include "ax.h" + +/* global variables */ +extern Pixel bg_pixel[ALH_ALARM_NSEV]; + +struct forcePVWindow { + void *area; + Widget menuButton; + Widget forcePVDialog; + Widget nameLabelW; + Widget nameTextW; + Widget forcePVnameTextW; + Widget forcePVdisabledToggleButton; + Widget forcePVmaskStringLabelW; + Widget forceMaskToggleButtonW[ALARM_NMASK]; + Widget forcePVforceValueTextW; + Widget forcePVresetValueTextW; + Widget forcePVCalcExpressionTextW; + Widget forcePVCalcPVTextW[NO_OF_CALC_PVS]; +}; + +/* forward declarations */ +static void forcePVApplyCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void forcePVCancelCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void forcePVDismissCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void forcePVHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void forcePVCreateDialog(ALINK*area); +static void forcePVUpdateDialogWidgets(struct forcePVWindow *forcePVWindow); +static void forcePVMaskChangeCallback( Widget widget, XtPointer calldata, XtPointer cbs); +static void forcePVUpdateFields(GCLINK* gclink,FORCEPV* pfPV,int context); +static void forcePVCalcPerform(GCLINK* gclink,int linktype,int forcePVChanged); +static void forcePVNewValueEvent(GCLINK* gclink,short linktype,double value); + + +/****************************************************** + forcePVUpdateDialog +******************************************************/ +void forcePVUpdateDialog(ALINK *area) +{ + struct forcePVWindow *forcePVWindow; + + forcePVWindow = (struct forcePVWindow *)area->forcePVWindow; + + if (!forcePVWindow) return; + + if (!forcePVWindow->forcePVDialog || + !XtIsManaged(forcePVWindow->forcePVDialog)) return; + + forcePVUpdateDialogWidgets(forcePVWindow); +} + +/****************************************************** + forcePVShowDialog +******************************************************/ +void forcePVShowDialog(ALINK *area,Widget menuButton) +{ + struct forcePVWindow *forcePVWindow; + + forcePVWindow = (struct forcePVWindow *)area->forcePVWindow; + + /* dismiss Dialog */ + if (forcePVWindow && forcePVWindow->forcePVDialog && + XtIsManaged(forcePVWindow->forcePVDialog)) { + forcePVDismissCallback(NULL, (XtPointer)forcePVWindow, NULL); + return; + } + + /* create forcePVWindow and Dialog Widgets if necessary */ + if (!forcePVWindow) forcePVCreateDialog(area); + + /* update forcePVWindow link info */ + forcePVWindow = (struct forcePVWindow *)area->forcePVWindow; + forcePVWindow->menuButton = menuButton; + + /* update Dialog Widgets */ + forcePVUpdateDialogWidgets(forcePVWindow); + + /* show Dialog */ + if (!forcePVWindow->forcePVDialog) return; + if (!XtIsManaged(forcePVWindow->forcePVDialog)) { + XtManageChild(forcePVWindow->forcePVDialog); + } + XMapWindow(XtDisplay(forcePVWindow->forcePVDialog), + XtWindow(XtParent(forcePVWindow->forcePVDialog))); + if (menuButton) XtVaSetValues(menuButton, XmNset, TRUE, NULL); +} + +/****************************************************** + forcePVUpdateDialogWidgets +******************************************************/ +static void forcePVUpdateDialogWidgets(struct forcePVWindow *forcePVWindow) +{ + struct gcData *pgcData; + GCLINK *link; + int i,linkType; + XmString string,oldString; + char buff[MAX_STRING_LENGTH]; + char buff1[MAX_STRING_LENGTH]; + MASK mask; + Boolean sameName; + + if (! forcePVWindow || !forcePVWindow->forcePVDialog ) return; + + link =getSelectionLinkArea(forcePVWindow->area); + + if (!link) { + string = XmStringCreateSimple(""); + XtVaSetValues(forcePVWindow->nameTextW,XmNlabelString, string, NULL); + XmStringFree(string); + return; + } else { + pgcData = link->pgcData; + linkType =getSelectionLinkTypeArea(forcePVWindow->area); + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + if (linkType == GROUP) string = XmStringCreateSimple("Group Name:"); + else string = XmStringCreateSimple("Channel Name:"); + XtVaSetValues(forcePVWindow->nameLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + + if (pgcData->alias){ + string = XmStringCreateSimple(pgcData->alias); + } else { + if (pgcData->name) string = XmStringCreateSimple(pgcData->name); + } + } + XtVaGetValues(forcePVWindow->nameTextW, XmNlabelString, &oldString, NULL); + XtVaSetValues(forcePVWindow->nameTextW, XmNlabelString, string, NULL); + sameName = XmStringCompare(string, oldString); + XmStringFree(string); + XmStringFree(oldString); + + if (!link || !pgcData->pforcePV || !sameName ) { + XmToggleButtonGadgetSetState(forcePVWindow->forcePVdisabledToggleButton, + FALSE,FALSE); + XmTextFieldSetString(forcePVWindow->forcePVnameTextW,""); + string = XmStringCreateSimple("-----"); + XtVaSetValues(forcePVWindow->forcePVmaskStringLabelW, + XmNlabelString,string,NULL); + XmStringFree(string); + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[0], + FALSE,TRUE); + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[1], + FALSE,TRUE); + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[2], + FALSE,TRUE); + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[3], + FALSE,TRUE); + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[4], + FALSE,TRUE); + + XmTextFieldSetString(forcePVWindow->forcePVforceValueTextW,""); + XmTextFieldSetString(forcePVWindow->forcePVresetValueTextW,""); + XmTextFieldSetString(forcePVWindow->forcePVCalcExpressionTextW,""); + for (i=0;i<NO_OF_CALC_PVS;i++){ + XmTextFieldSetString(forcePVWindow->forcePVCalcPVTextW[i],""); + } + if (!link || !pgcData->pforcePV) return; + } + + /* --------------------------------- + Force Process Variable + --------------------------------- */ + if(pgcData->pforcePV->name) + XmTextFieldSetString(forcePVWindow->forcePVnameTextW,pgcData->pforcePV->name); + else XmTextFieldSetString(forcePVWindow->forcePVnameTextW,""); + + XmToggleButtonGadgetSetState(forcePVWindow->forcePVdisabledToggleButton, + (Boolean)pgcData->pforcePV->disabled,FALSE); + + alGetMaskString(pgcData->pforcePV->forceMask,buff); + string = XmStringCreateSimple(buff); + XtVaSetValues(forcePVWindow->forcePVmaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + + mask = pgcData->pforcePV->forceMask; + if (mask.Cancel == 1 ) + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[0], + TRUE,TRUE); + else XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[0], + FALSE,TRUE); + if (mask.Disable == 1 ) + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[1], + TRUE,TRUE); + else XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[1], + FALSE,TRUE); + if (mask.Ack == 1 ) + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[2], + TRUE,TRUE); + else XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[2], + FALSE,TRUE); + if (mask.AckT == 1 ) + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[3], + TRUE,TRUE); + else XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[3], + FALSE,TRUE); + if (mask.Log == 1 ) + XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[4], + TRUE,TRUE); + else XmToggleButtonSetState(forcePVWindow->forceMaskToggleButtonW[4], + FALSE,TRUE); + + sprintf(buff,"%g",pgcData->pforcePV->forceValue); + XmTextFieldSetString(forcePVWindow->forcePVforceValueTextW,buff); + + sprintf(buff1,"%g",pgcData->pforcePV->resetValue); + if (!strcmp(buff,buff1)) sprintf(buff,"%s","NE"); + else sprintf(buff,"%g",pgcData->pforcePV->resetValue); + XmTextFieldSetString(forcePVWindow->forcePVresetValueTextW,buff); + + if(pgcData->pforcePV->pcalc){ + if (pgcData->pforcePV->pcalc->expression) + XmTextFieldSetString(forcePVWindow->forcePVCalcExpressionTextW, + pgcData->pforcePV->pcalc->expression); + else XmTextFieldSetString(forcePVWindow->forcePVCalcExpressionTextW,""); + for (i=0;i<NO_OF_CALC_PVS;i++){ + if (pgcData->pforcePV->pcalc->name[i]) + XmTextFieldSetString(forcePVWindow->forcePVCalcPVTextW[i], + pgcData->pforcePV->pcalc->name[i]); + else XmTextFieldSetString(forcePVWindow->forcePVCalcPVTextW[i],""); + } + } else { + XmTextFieldSetString(forcePVWindow->forcePVCalcExpressionTextW,""); + for (i=0;i<NO_OF_CALC_PVS;i++){ + XmTextFieldSetString(forcePVWindow->forcePVCalcPVTextW[i],""); + } + } +} + +/****************************************************** + forcePVCreateDialog +******************************************************/ +static void forcePVCreateDialog(ALINK *area) +{ + struct forcePVWindow *forcePVWindow; + + Widget forcePVDialogShell, forcePVDialog; + Widget form; + Widget nameLabelW, nameTextW; + Widget forcePVdisabledToggleButton; + Widget forceMaskToggleButtonW[ALARM_NMASK]; + Widget forcePVforceValueLabel,forcePVnameTextW, forcePVforceValueTextW, + forcePVresetValueTextW, forcePVresetValueLabel; + Widget forcePVmaskStringLabelW, frame2, form2, frame3, + rowcol3; + Widget forceMaskLabel, forcePVnameLabel; + Widget prev; + Widget frame4, form3, forcePVCalcLabel,forcePVCalcExpressionLabel; + Widget forcePVCalcExpressionTextW; + Widget forcePVCalcPVLabel[NO_OF_CALC_PVS], forcePVCalcPVTextW[NO_OF_CALC_PVS]; + int i; + Pixel textBackground; + XmString string; + char letter[]={"ABCDEF"}; + char pvid[]="A "; + static ActionAreaItem forcePV_items[] = { + { "Apply", forcePVApplyCallback, NULL }, + { "Cancel", forcePVCancelCallback, NULL }, + { "Dismiss", forcePVDismissCallback, NULL }, + { "Help", forcePVHelpCallback, NULL }, + }; + static String maskFields[] = { + "Cancel Alarm", + "Disable Alarm", + "NoAck Alarm", + "NoAck Transient Alarm", + "NoLog Alarm" + }; + + if (!area) return; + + forcePVWindow = (struct forcePVWindow *)area->forcePVWindow; + + if (forcePVWindow && forcePVWindow->forcePVDialog){ + if (XtIsManaged(forcePVWindow->forcePVDialog)) return; + else XtManageChild(forcePVWindow->forcePVDialog); + } + + textBackground = bg_pixel[3]; + + forcePVWindow = (struct forcePVWindow *)calloc(1,sizeof(struct forcePVWindow)); + area->forcePVWindow = (void *)forcePVWindow; + forcePVWindow->area = (void *)area; + + forcePVDialogShell = XtVaCreatePopupShell("Force Process Variable", + transientShellWidgetClass, area->toplevel, NULL); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(forcePVDialogShell, + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(forcePVDialogShell), + "WM_DELETE_WINDOW", False); + XmAddWMProtocolCallback(forcePVDialogShell,WM_DELETE_WINDOW, + (XtCallbackProc)forcePVDismissCallback, (XtPointer)forcePVWindow); + } + + forcePVDialog = XtVaCreateWidget("forcePVDialog", + xmPanedWindowWidgetClass, forcePVDialogShell, + XmNsashWidth, 1, + XmNsashHeight, 1, + XmNuserData, area, + (XtPointer)NULL); + + form = XtVaCreateWidget("control_area", + xmFormWidgetClass, forcePVDialog, + NULL); + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + nameLabelW = XtVaCreateManagedWidget("nameLabelW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_END, + XmNtopAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + XmNrecomputeSize, True, + NULL); + + nameTextW = XtVaCreateManagedWidget("nameTextW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 50, + XmNrecomputeSize, True, + NULL); + + + /* --------------------------------- + Force Process Variable + --------------------------------- */ + + frame2 = XtVaCreateWidget("frame2", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, nameLabelW, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + NULL); + + form2 = XtVaCreateWidget("form2", + xmFormWidgetClass, frame2, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNspacing, 0, + XmNmarginHeight, 0, + NULL); + + forcePVdisabledToggleButton = XtVaCreateManagedWidget( + "ForcePV Disabled", + xmToggleButtonGadgetClass, form2, + NULL); + + string = XmStringCreateSimple("Force Process Variable Name (or CALC):"); + forcePVnameLabel = XtVaCreateManagedWidget("forcePVnameLabel", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVdisabledToggleButton, + XmNtopOffset, 10, + NULL); + XmStringFree(string); + + forcePVnameTextW = XtVaCreateManagedWidget("forcePVnameTextW", + xmTextFieldWidgetClass, form2, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 30, + XmNmaxLength, PVNAME_SIZE, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVnameLabel, + XmNleftAttachment, XmATTACH_FORM, + (XtPointer)NULL); + + XtAddCallback(forcePVnameTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + string = XmStringCreateSimple("Force Mask "); + forceMaskLabel = XtVaCreateManagedWidget("forceMaskLabel", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVnameTextW, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + prev = forceMaskLabel; + + string = XmStringCreateSimple("-----"); + forcePVmaskStringLabelW = XtVaCreateManagedWidget("forcePVmaskStringLabelW", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVnameTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forceMaskLabel, + NULL); + XmStringFree(string); + + frame3 = XtVaCreateManagedWidget("frame3", + xmFrameWidgetClass, form2, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_FORM, + NULL); + prev = frame3; + + rowcol3 = XtVaCreateWidget("rowcol3", + xmRowColumnWidgetClass, frame3, + XmNspacing, 0, + XmNmarginHeight, 0, + NULL); + + for (i = 0; i < ALARM_NMASK; i++){ + long ilong=i; + forceMaskToggleButtonW[i] = XtVaCreateManagedWidget(maskFields[i], + xmToggleButtonGadgetClass, rowcol3, + XmNmarginHeight, 0, + XmNuserData, (XtPointer)forcePVmaskStringLabelW, + NULL); + XtAddCallback(forceMaskToggleButtonW[i], XmNvalueChangedCallback, + (XtCallbackProc)forcePVMaskChangeCallback, (XtPointer)ilong); + } + + XtManageChild(rowcol3); + + string = XmStringCreateSimple("Force Value "); + forcePVforceValueLabel = XtVaCreateManagedWidget("forcePVvalue", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + forcePVforceValueTextW = XtVaCreateManagedWidget("forcePVforceValueTextW", + xmTextFieldWidgetClass, form2, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 8, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVforceValueLabel, + NULL); + + XtAddCallback(forcePVforceValueTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + string = XmStringCreateSimple("Reset Value "); + forcePVresetValueLabel = XtVaCreateManagedWidget("forcePVresetValueLabel", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVforceValueLabel, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + forcePVresetValueTextW = XtVaCreateManagedWidget("forcePVresetValueTextW", + xmTextFieldWidgetClass, form2, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 8, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVforceValueTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVresetValueLabel, + NULL); + + XtAddCallback(forcePVresetValueTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + frame4 = XtVaCreateManagedWidget("frame4", + xmFrameWidgetClass, form2, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVresetValueTextW, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + form3 = XtVaCreateWidget("form3", + xmFormWidgetClass, frame4, + XmNspacing, 0, + XmNmarginHeight, 0, + NULL); + + string = XmStringCreateSimple("Force CALC"); + forcePVCalcLabel = XtVaCreateManagedWidget("forcePVCalcLabel", + xmLabelGadgetClass, form3, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVresetValueLabel, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple("Expression: "); + forcePVCalcExpressionLabel = XtVaCreateManagedWidget("forcePVCalcExpression", + xmLabelGadgetClass, form3, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVCalcLabel, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + forcePVCalcExpressionTextW = XtVaCreateManagedWidget("forcePVCalcExpressionTextW", + xmTextFieldWidgetClass, form3, + XmNspacing, 0, + XmNmarginHeight, 0, +/* + XmNcolumns, 40, + XmNmaxLength, 100, +*/ + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVCalcExpressionLabel, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtAddCallback(forcePVforceValueTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + prev = forcePVCalcExpressionTextW; + + for (i=0;i<NO_OF_CALC_PVS;i++) { + + pvid[0]=letter[i]; + string = XmStringCreateSimple(pvid); + + forcePVCalcPVLabel[i] = XtVaCreateManagedWidget("forcePVCalcPVLabel", + xmLabelGadgetClass, form3, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + forcePVCalcPVTextW[i] = XtVaCreateManagedWidget("forcePVCalcPVTextW", + xmTextFieldWidgetClass, form3, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 30, + XmNmaxLength, PVNAME_SIZE, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVCalcPVLabel[i], +#if 0 + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, +#endif + (XtPointer)NULL); + + prev = forcePVCalcPVTextW[i]; + + XtAddCallback(forcePVCalcPVTextW[i], XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + } + + /* Set the client data "Apply", "Cancel", "Dismiss" and "Help" button's callbacks. */ + forcePV_items[0].data = (XtPointer)forcePVWindow; + forcePV_items[1].data = (XtPointer)forcePVWindow; + forcePV_items[2].data = (XtPointer)forcePVWindow; + forcePV_items[3].data = (XtPointer)forcePVWindow; + + (void)createActionButtons(forcePVDialog, forcePV_items, XtNumber(forcePV_items)); + + forcePVWindow->forcePVDialog = forcePVDialog; + forcePVWindow->nameLabelW = nameLabelW; + forcePVWindow->nameTextW = nameTextW; + forcePVWindow->forcePVdisabledToggleButton = forcePVdisabledToggleButton; + forcePVWindow->forcePVnameTextW = forcePVnameTextW; + forcePVWindow->forcePVmaskStringLabelW = forcePVmaskStringLabelW; + forcePVWindow->forcePVforceValueTextW = forcePVforceValueTextW; + forcePVWindow->forcePVresetValueTextW = forcePVresetValueTextW; + forcePVWindow->forcePVCalcExpressionTextW = forcePVCalcExpressionTextW; + + for (i=0;i<NO_OF_CALC_PVS;i++) { + forcePVWindow->forcePVCalcPVTextW[i] = forcePVCalcPVTextW[i]; + } + + for (i = 0; i < ALARM_NMASK; i++){ + forcePVWindow->forceMaskToggleButtonW[i] = forceMaskToggleButtonW[i]; + } + + /* update forcePVWindow link info */ + forcePVUpdateDialogWidgets(forcePVWindow); + + /* RowColumn is full -- now manage */ + XtManageChild(form3); + + /* RowColumn is full -- now manage */ + XtManageChild(form2); + + XtManageChild(frame2); + XtManageChild(form); + + XtManageChild(forcePVDialog); + + XtRealizeWidget(forcePVDialogShell); + +} + +/****************************************************** + forcePVMaskChangeCallback +******************************************************/ +static void forcePVMaskChangeCallback(Widget widget, XtPointer calldata, +XtPointer cbs) +{ + int index=(long)calldata; + char *mask; + Widget maskWidget; + XmString string; + + XtVaGetValues(widget, XmNuserData, &maskWidget, NULL); + + XtVaGetValues(maskWidget, XmNlabelString, &string, NULL); + XmStringGetLtoR(string, XmFONTLIST_DEFAULT_TAG, &mask); + XmStringFree(string); + + if (!XmToggleButtonGadgetGetState(widget)) { + mask[index] = '-'; + } + else { + switch (index) { + case ALARMCANCEL: + mask[index] = 'C'; + break; + case ALARMDISABLE: + mask[index] = 'D'; + break; + case ALARMACK: + mask[index] = 'A'; + break; + case ALARMACKT: + mask[index] = 'T'; + break; + case ALARMLOG: + mask[index] = 'L'; + break; + } + } + + string = XmStringCreateSimple(mask); + XtVaSetValues(maskWidget, XmNlabelString, string, NULL); + XmStringFree(string); + XtFree(mask); +} + +/****************************************************** + forcePVApplyCallback +******************************************************/ +static void forcePVApplyCallback(Widget widget, XtPointer calldata, +XtPointer cbs) +{ + struct forcePVWindow *forcePVWindow= (struct forcePVWindow *)calldata; + double dbl; + int rtn,i; + XmString string; + char *buff; + GCLINK *link; + int linkType; + FORCEPV forcePV; + FORCEPV_CALC calc; + FORCEPV* pforcePV; + FORCEPV_CALC* pcalc; + char buff1[6]; + + link =getSelectionLinkArea(forcePVWindow->area); + if (!link) return; + linkType =getSelectionLinkTypeArea(forcePVWindow->area); + + pforcePV=&forcePV; + pforcePV->pcalc=&calc; + pcalc=pforcePV->pcalc; + + /* initialize */ + pforcePV->name=0; + pcalc->expression=0; + for (i=0;i<NO_OF_CALC_PVS;i++) pcalc->name[i]=0; + + /* --------------------------------- + Force Process Variable + --------------------------------- */ + /* update link field - forcePVMask */ + XtVaGetValues(forcePVWindow->forcePVmaskStringLabelW, XmNlabelString, &string, NULL); + XmStringGetLtoR(string,XmFONTLIST_DEFAULT_TAG,&buff); + XmStringFree(string); + alSetMask(buff,&(pforcePV->forceMask)); + XtFree(buff); + + /* update link field - pforcePV->forceValue */ + buff = XmTextFieldGetString(forcePVWindow->forcePVforceValueTextW); + dbl=0; + rtn = sscanf(buff,"%lf",&dbl); + if (rtn == 1) pforcePV->forceValue = dbl; + else pforcePV->forceValue = 1; + XtFree(buff); + + /* update link field - pforcePV->resetValue */ + buff = XmTextFieldGetString(forcePVWindow->forcePVresetValueTextW); + if (strncmp(buff,"NE",2)==0 || strncmp(buff,"ne",2)==0) { + pforcePV->resetValue = pforcePV->forceValue; + } else { + dbl=0; + rtn = sscanf(buff,"%lf",&dbl); + if (rtn == 1) pforcePV->resetValue = dbl; + else pforcePV->resetValue = 0; + } + XtFree(buff); + + /* update link field - pforcePV->name */ + buff = XmTextFieldGetString(forcePVWindow->forcePVnameTextW); + if (strlen(buff)) pforcePV->name=buff; + else { + pforcePV->name=0; + XtFree(buff); + } + + /* update disabled field - pforcePV->disabled */ + pforcePV->disabled=XmToggleButtonGadgetGetState(forcePVWindow->forcePVdisabledToggleButton); + + /* CALC expression */ + buff = XmTextFieldGetString(forcePVWindow->forcePVCalcExpressionTextW); + if (strlen(buff)) pcalc->expression = buff; + else { + pcalc->expression=0; + XtFree(buff); + } + + for (i=0;i<NO_OF_CALC_PVS;i++) { + buff = XmTextFieldGetString(forcePVWindow->forcePVCalcPVTextW[i]); + if (strlen(buff)) pcalc->name[i]=buff; + else { + pcalc->name[i]=0; + XtFree(buff); + } + } + + forcePVUpdateFields(link,pforcePV,linkType); + + if (linkType == GROUP){ + awGetMaskString(((GLINK*)link)->pgroupData->mask,buff1); + alLogOpModMessage(FORCE_MASK_GROUP,link, + " Group forcePV modified <%s> [%g] [%s]", + buff1, + link->pgcData->pforcePV->forceValue, + link->pgcData->pforcePV->name ? link->pgcData->pforcePV->name : " "); + + }else { + alGetMaskString(((CLINK*)link)->pchanData->curMask,buff1); + alLogOpModMessage(FORCE_MASK,(GCLINK*)link, + "Channel forcePV modified <%s> [%g] [%s]", + buff1, + link->pgcData->pforcePV->forceValue, + link->pgcData->pforcePV->name ? link->pgcData->pforcePV->name : " "); + } + + /* --------------------------------- + Update dialog windows + --------------------------------- */ + axUpdateDialogs(forcePVWindow->area); + + /* free memory */ + if (pforcePV->name) XtFree(pforcePV->name); + if (pcalc->expression) XtFree(pcalc->expression); + for (i=0;i<NO_OF_CALC_PVS;i++) { + if (pcalc->name[i]) XtFree(pcalc->name[i]); + } +} + +/****************************************************** + forcePVHelpCallback +******************************************************/ +static void forcePVHelpCallback(Widget widget, XtPointer calldata, +XtPointer cbs) +{ + char *message1 = + "Create or modify forcePV values for a selected group or channel.\n" + " \n" + "NOTE: The force value must be set to a value" + " different from the reset value.\n" + " \n" + "Press the Apply button to change the forcePV" + " values for the group or channel.\n" + "Press the Cancel button to abort current change.\n" + "Press the Dismiss button to close the Force PV dialog window.\n" + "Press the Help button to get this help description window.\n" + ; + char *message2 = " "; + + createDialog(widget,XmDIALOG_INFORMATION, message1,message2); +} + +/****************************************************** + forcePVDismissCallback +******************************************************/ +static void forcePVDismissCallback(Widget widget, XtPointer calldata, +XtPointer cbs) +{ + struct forcePVWindow *forcePVWindow= (struct forcePVWindow *)calldata; + Widget forcePVDialog; + + forcePVDialog = forcePVWindow->forcePVDialog; + XtUnmanageChild(forcePVDialog); + XUnmapWindow(XtDisplay(forcePVDialog), XtWindow(XtParent(forcePVDialog))); + if (forcePVWindow->menuButton) + XtVaSetValues(forcePVWindow->menuButton, XmNset, FALSE, NULL); +} + +/****************************************************** + forcePVCancelCallback +******************************************************/ +static void forcePVCancelCallback(Widget widget, XtPointer calldata, +XtPointer cbs) +{ + struct forcePVWindow *forcePVWindow= (struct forcePVWindow *)calldata; + forcePVUpdateDialog((ALINK *)(forcePVWindow->area)); +} + + +/************************************************************** + Free forcePV calc memory +*************************************************************/ +static void forcePVCalcDelete(FORCEPV_CALC** ppcalc) +{ + FORCEPV_CALC* pcalc=*ppcalc; + int i; + + if (!ppcalc || !pcalc) return; + if (pcalc->expression) free(pcalc->expression); + if (pcalc->rpbuf) free(pcalc->rpbuf); + for (i=0;i<NO_OF_CALC_PVS;i++) { + if (pcalc->puser[i]) free(pcalc->puser[i]); + if (pcalc->evid[i]) alCaClearEvent(&pcalc->evid[i]); + if (pcalc->chid[i]) alCaClearChannel(&pcalc->chid[i]); + if (pcalc->name[i]) free(pcalc->name[i]); + } + free(pcalc); + ppcalc=0; +} + +/************************************************************** + Delete forcePV +*************************************************************/ +void alForcePVDelete(FORCEPV** ppforcePV) +{ + FORCEPV* pforcePV=*ppforcePV; + + if (!ppforcePV || !pforcePV) return; + alCaClearEvent(&pforcePV->evid); + if (pforcePV->puser) free(pforcePV->puser); + alCaClearChannel(&pforcePV->chid); + alCaClearChannel(&pforcePV->chid); + if (pforcePV->name) free(pforcePV->name); + forcePVCalcDelete(&pforcePV->pcalc); + free(pforcePV); + pforcePV=0; +} + +/************************************************************** + Copy forcePV - DO NOT COPY CHANNEL ACCESS FIELDS +*************************************************************/ +FORCEPV* alForcePVCopy(FORCEPV* pforcePV) +{ + FORCEPV* pnew; + int i; + + if (!pforcePV) return 0; + pnew=(FORCEPV*)calloc(1,sizeof(FORCEPV)); + if (pforcePV->name){ + pnew->name = (char *)calloc(strlen(pforcePV->name)+1,sizeof(char)); + strcpy(pforcePV->name,pnew->name); + } + pnew->forceValue=pforcePV->forceValue; + pnew->resetValue=pforcePV->resetValue; + pnew->disabled=pforcePV->disabled; + pnew->forceMask=pforcePV->forceMask; + + if (!pforcePV->pcalc) return pnew; + pnew->pcalc=(FORCEPV_CALC*)calloc(1,sizeof(FORCEPV_CALC)); + if (pforcePV->pcalc->expression){ + pnew->pcalc->expression=(char *)calloc(strlen(pforcePV->pcalc->expression)+1,sizeof(char)); + strcpy(pforcePV->pcalc->expression,pnew->pcalc->expression); + } + if (pforcePV->pcalc->rpbuf){ + pnew->pcalc->rpbuf=(char*)calloc(strlen(pforcePV->pcalc->rpbuf)+1,sizeof(char)); + strcpy(pforcePV->pcalc->rpbuf,pnew->pcalc->rpbuf); + } + for (i=0;i<NO_OF_CALC_PVS;i++) { + if (pforcePV->pcalc->name[i]){ + pnew->pcalc->name[i]=(char*)calloc(strlen(pforcePV->pcalc->name[i])+1,sizeof(char)); + strcpy(pforcePV->pcalc->name[i],pnew->pcalc->name[i]); + } + } + return pnew; +} + +/************************************************************** + alForcePVClearCA +*************************************************************/ +void alForcePVClearCA(FORCEPV* pforcePV) +{ + FORCEPV_CALC* pcalc; + int i; + + if (!pforcePV) return; + if (pforcePV->puser) free(pforcePV->puser); + pforcePV->puser=0; + if (pforcePV->evid) alCaClearEvent(&pforcePV->evid); + if (pforcePV->chid) alCaClearChannel(&pforcePV->chid); + if (!pforcePV->pcalc) return; + pcalc=pforcePV->pcalc; + for (i=0;i<NO_OF_CALC_PVS;i++) { + if (pcalc->puser[i]) free(pcalc->puser[i]); + pcalc->puser[i]=0; + if (pcalc->evid[i]) alCaClearEvent(&pcalc->evid[i]); + if (pcalc->chid[i]) alCaClearChannel(&pcalc->chid[i]); + } +} + + +/************************************************************** + alForcePVSetNotConnected +*************************************************************/ +void alForcePVSetNotConnected(FORCEPV* pforcePV,char* name) +{ + FORCEPV_CALC* pcalc; + int i; + + if (!pforcePV) return; + if ( pforcePV->chid && !alCaIsConnected(pforcePV->chid) ) { + errMsg("Force PV %s for %s Not Connected\n", + pforcePV->name, name); + } + pcalc=pforcePV->pcalc; + if (pforcePV->pcalc) { + for (i=0;i<NO_OF_CALC_PVS;i++) { + if ( pforcePV->pcalc->chid[i] && + !alCaIsConnected(pforcePV->pcalc->chid[i]) ) { + errMsg("Force CALC PV %s for %s Not Connected\n", + pforcePV->pcalc->name[i], name); + } + } + } +} + +/************************************************************** + forcePVUpdateFields +*************************************************************/ +void forcePVUpdateFields(GCLINK* gclink,FORCEPV* pfPV,int context) +{ + FORCEPV* pforcePV; + int i=0; + long status=0; + short err=0; + short disabledHold; + FORCEPV_CALC* pcalc; + FORCEPV_CALC* pcalcNew; + FORCEPVCADATA* puser; + char buf[MAX_STRING_LENGTH]; + double holdValue; + ALINK *area = gclink->pmainGroup->area; + + if (!gclink->pgcData->pforcePV) + gclink->pgcData->pforcePV=(FORCEPV*)calloc(1,sizeof(FORCEPV)); + pforcePV=gclink->pgcData->pforcePV; + + /* temporarily disable forcePV */ + disabledHold=pforcePV->disabled; + pforcePV->disabled=YES; + + if (pforcePV->forceValue != pfPV->forceValue) pforcePV->forceValue=pfPV->forceValue; + if (pforcePV->resetValue != pfPV->resetValue) pforcePV->resetValue=pfPV->resetValue; + pforcePV->forceMask=pfPV->forceMask; + + if (pfPV->name){ + if (!pforcePV->name || strcmp(pforcePV->name,pfPV->name)){ + if (pforcePV->name){ + free(pforcePV->name); + pforcePV->name=0; + /* cancel channel access */ + if (pforcePV->puser) free(pforcePV->puser); + pforcePV->puser=0; + if (pforcePV->evid) alCaClearEvent(&pforcePV->evid); + if (pforcePV->chid) alCaClearChannel(&pforcePV->chid); + } + pforcePV->name = (char *)calloc(strlen(pfPV->name)+1,sizeof(char)); + strcpy(pforcePV->name,pfPV->name); + if (strlen(pforcePV->name) && strcmp(pforcePV->name,"CALC")) { + /* start channel access */ + pforcePV->currentValue = -999; + alCaConnectForcePV(pforcePV->name,&pforcePV->chid,gclink->pgcData->name); + puser=(FORCEPVCADATA *)calloc(1,sizeof(FORCEPVCADATA)); + puser->index=-1; + puser->link=gclink; + puser->linktype=context; + if (pforcePV->puser) free(pforcePV->puser); + pforcePV->puser = puser; + alCaAddForcePVEvent (pforcePV->chid,puser,&pforcePV->evid); + } + } + } else { + if (pforcePV->name){ + free(pforcePV->name); + pforcePV->name=0; + /* cancel channel access */ + if (pforcePV->puser) free(pforcePV->puser); + pforcePV->puser=0; + if (pforcePV->evid) alCaClearEvent(&pforcePV->evid); + if (pforcePV->chid) alCaClearChannel(&pforcePV->chid); + } + } + + /* update expression */ + if (pfPV->pcalc->expression){ + if (!pforcePV->pcalc) pforcePV->pcalc=(FORCEPV_CALC*)calloc(1,sizeof(FORCEPV_CALC)); + if (!pforcePV->pcalc->expression || + strcmp(pforcePV->pcalc->expression,pfPV->pcalc->expression)){ + if (pforcePV->pcalc->expression){ + free(pforcePV->pcalc->expression); + if (pforcePV->pcalc->rpbuf) free(pforcePV->pcalc->rpbuf); + } + pforcePV->pcalc->expression = + (char *)calloc(strlen(pfPV->pcalc->expression)+1,sizeof(char)); + strcpy(pforcePV->pcalc->expression,pfPV->pcalc->expression); + /* convert an algebraic expression to symbolic postfix */ + status=postfix(pforcePV->pcalc->expression,buf,&err); + if(status || err) { + errMsg("Error converting '%s' to symbolic postfix: status=%ld err=%d\n", + pforcePV->pcalc->expression,status,err); + } else { + pforcePV->pcalc->rpbuf=(char*)calloc(strlen(buf)+1,sizeof(char)); + strcpy(pforcePV->pcalc->rpbuf,buf); + } + } + } else { + if (pforcePV->pcalc){ + if (pforcePV->pcalc->expression) free(pforcePV->pcalc->expression); + pforcePV->pcalc->expression=0; + if (pforcePV->pcalc->rpbuf) free(pforcePV->pcalc->rpbuf); + pforcePV->pcalc->rpbuf=0; + } + } + + pcalc=pforcePV->pcalc; + pcalcNew=pfPV->pcalc; + /* update CALC pv names */ + for (i=0;i<NO_OF_CALC_PVS;i++) { + if (pcalcNew->name[i]){ + if (!pcalc) pcalc=(FORCEPV_CALC*)calloc(1,sizeof(FORCEPV_CALC)); + if (!pcalc->name[i] || + strcmp(pcalc->name[i],pcalcNew->name[i])){ + if (pcalc->name[i]){ + free(pcalc->name[i]); + pcalc->name[i]=0; + pcalc->value[i] = -999; + /* cancel channel access */ + if (pcalc->puser[i]) free(pcalc->puser[i]); + pcalc->puser[i]=0; + if (pcalc->evid[i]) alCaClearEvent(&pcalc->evid[i]); + if (pcalc->chid[i]) alCaClearChannel(&pcalc->chid[i]); + } + pcalc->name[i] = + (char *)calloc(strlen(pcalcNew->name[i])+1,sizeof(char)); + strcpy(pcalc->name[i],pcalcNew->name[i]); + if (strlen(pcalc->name[i]) && strcmp(pcalc->name[i],"CALC")) { + if (!isalpha(*pcalcNew->name[i])) { + pcalc->value[i] = atof(pcalcNew->name[i]); + }else { + /* start channel access */ + pcalc->value[i] = -999; + alCaConnectForcePV(pcalc->name[i],&pcalc->chid[i], + gclink->pgcData->name); + puser=(FORCEPVCADATA *)calloc(1,sizeof(FORCEPVCADATA)); + puser->index=i; + puser->link=gclink; + puser->linktype=context; + if (pcalc->puser[i]) free(pcalc->puser[i]); + pcalc->puser[i] = puser; + alCaAddForcePVEvent(pcalc->chid[i],puser,&pcalc->evid[i]); + } + } + } + } else { + if (pcalc){ + if (pcalc->name[i]==0) continue; + free(pcalc->name[i]); + pcalc->name[i]=0; + pcalc->value[i] = -999; + /* cancel channel access */ + if (pcalc->puser[i]) free(pcalc->puser[i]); + pcalc->puser[i]=0; + if (pcalc->evid[i]) alCaClearEvent(&pcalc->evid[i]); + if (pcalc->chid[i]) alCaClearChannel(&pcalc->chid[i]); + } + } + } + pforcePV->pcalc=pcalc; + pforcePV->disabled=pfPV->disabled; + updateDisabledForcePVCount(area,(int)(pforcePV->disabled-disabledHold)); + + if (pforcePV->name && strcmp(pforcePV->name,"CALC")==0) + forcePVCalcPerform(gclink,context,1); + else { + holdValue=pforcePV->currentValue; + pforcePV->currentValue = -999; + forcePVNewValueEvent(gclink,(short)context,holdValue); + } +} + +/******************************************************************* + ForcePV New Value Event +*******************************************************************/ +static void forcePVNewValueEvent(GCLINK* gclink,short linktype,double value) +{ + struct gcData *pgcData; + FORCEPV* pforcePV; + char buff1[6]; + char buff2[20]; + + pgcData=gclink->pgcData; + pforcePV=pgcData->pforcePV; + if (!pforcePV) return; + if (!alCaIsConnected(pforcePV->chid)) return; + + if (!pforcePV->disabled) { + if (pforcePV->currentValue==value) return; + if (value==pforcePV->forceValue) { + if (linktype==GROUP){ + alChangeGroupMask((GLINK*)gclink,pforcePV->forceMask); + awGetMaskString(((GLINK*)gclink)->pgroupData->mask,buff1); + alLogOpModMessage(FORCE_MASK_GROUP,gclink, + "Group forcePV FORCE <%s> [%g] [%s]", + buff1, + pforcePV->forceValue, + pforcePV->name); + } else { + alChangeChanMask((CLINK*)gclink,pforcePV->forceMask); + alGetMaskString(((CLINK*)gclink)->pchanData->curMask,buff1); + alLogOpModMessage(FORCE_MASK,gclink, + "Channel forcePV FORCE <%s> [%g] [%s]", + buff1, + pforcePV->forceValue, + pforcePV->name); + } + alCaFlushIo(); + } + else if ( ( (pforcePV->currentValue == -999 || + pforcePV->currentValue == pforcePV->forceValue) && + pforcePV->forceValue == pforcePV->resetValue ) || + ( value == pforcePV->resetValue && + pforcePV->forceValue != pforcePV->resetValue ) ) { + if (linktype==GROUP){ + alResetGroupMask((GLINK*)gclink); + awGetMaskString(((GLINK*)gclink)->pgroupData->mask,buff1); + if (pforcePV->resetValue == pforcePV->forceValue ) + sprintf(buff2,"%s %g","NE",pforcePV->forceValue); + else sprintf(buff2,"%g",pforcePV->resetValue); + alLogOpModMessage(CHANGE_MASK_GROUP,gclink, + "Group forcePV RESET <%s> [%s] [%s]", + buff1, + buff2, + pforcePV->name); + + } else { + CLINK *clink=(CLINK*)gclink;; + alChangeChanMask(clink,clink->pchanData->defaultMask); + alGetMaskString(clink->pchanData->curMask,buff1); + if (pforcePV->resetValue == pforcePV->forceValue ) + sprintf(buff2,"%s %g","NE",pforcePV->forceValue); + else sprintf(buff2,"%g",pforcePV->resetValue); + alLogOpModMessage(CHANGE_MASK,gclink, + "Channel forcePV RESET <%s> [%s] [%s]", + buff1, + buff2, + pforcePV->name); + } + alCaFlushIo(); + } + } + pforcePV->currentValue=value; +} + + +/******************************************************************* + ForcePVCalc New Value Event +*******************************************************************/ +void alForcePVCalcNewValueEvent(GCLINK* gclink,short linktype,short index,double value) +{ + FORCEPV* pforcePV; + FORCEPV_CALC* pcalc; + + pforcePV=gclink->pgcData->pforcePV; + if (!pforcePV) return; + if (!pforcePV->pcalc) return; + pcalc=pforcePV->pcalc; + if (pcalc->value[index]==value) return; + pcalc->value[index]=value; + + forcePVCalcPerform(gclink,linktype,0); +} + +/******************************************************************* + ForcePVCalc Calculate expression value +*******************************************************************/ +static void forcePVCalcPerform(GCLINK* gclink,int linktype,int forcePVChanged) +{ + FORCEPV* pforcePV=gclink->pgcData->pforcePV; + FORCEPV_CALC* pcalc=gclink->pgcData->pforcePV->pcalc; + int i; + double calcValue=0; + long status =0; + char buff1[6]; + char buff2[20]; + + if (!pcalc) return; + + for (i=0;i<NO_OF_CALC_PVS;i++){ + if (pcalc->chid[i] && !alCaIsConnected(pcalc->chid[i])) return; + if (pcalc->value[i]==-999.) return; + } + if (!pcalc->rpbuf) return; + status=calcPerform(pcalc->value,&calcValue,pcalc->rpbuf); + if (status) errMsg("ForcePV calcPerform failed: status=%ld\n",status); + + if (!forcePVChanged && calcValue == pforcePV->currentValue) return; + + if (pforcePV->name && strcmp(pforcePV->name,"CALC")==0 && !pforcePV->disabled) { + if ((float)calcValue == (float)pforcePV->forceValue) { + if (linktype==GROUP){ + alChangeGroupMask((GLINK*)gclink,pforcePV->forceMask); + awGetMaskString(((GLINK*)gclink)->pgroupData->mask,buff1); + alLogOpModMessage(FORCE_MASK_GROUP,gclink, + "Group forcePV FORCE <%s> [%g] [%s]", + buff1, + pforcePV->forceValue, + pforcePV->name); + } else { + alChangeChanMask((CLINK*)gclink,pforcePV->forceMask); + alGetMaskString(((CLINK*)gclink)->pchanData->curMask,buff1); + alLogOpModMessage(FORCE_MASK,gclink, + "Channel forcePV FORCE <%s> [%g] [%s]", + buff1, + pforcePV->forceValue, + pforcePV->name); + } + alCaFlushIo(); + } else if (((pforcePV->currentValue == -999 || + pforcePV->currentValue == pforcePV->forceValue) && + pforcePV->forceValue == pforcePV->resetValue) || + ( (float)calcValue == (float)pforcePV->resetValue && + pforcePV->forceValue != pforcePV->resetValue) ){ + if (linktype==GROUP){ + alResetGroupMask((GLINK*)gclink); + awGetMaskString(((GLINK*)gclink)->pgroupData->mask,buff1); + if (pforcePV->resetValue == pforcePV->forceValue ) + sprintf(buff2,"%s %g","NE",pforcePV->forceValue); + else sprintf(buff2,"%g",pforcePV->resetValue); + alLogOpModMessage(CHANGE_MASK_GROUP,gclink, + "Group forcePV RESET <%s> [%s] [%s]", + buff1, + buff2, + pforcePV->name); + } else { + CLINK *clink=(CLINK*)gclink;; + alChangeChanMask(clink,clink->pchanData->defaultMask); + alGetMaskString(clink->pchanData->curMask,buff1); + if (pforcePV->resetValue == pforcePV->forceValue ) + sprintf(buff2,"%s %g","NE",pforcePV->forceValue); + else sprintf(buff2,"%g",pforcePV->resetValue); + alLogOpModMessage(CHANGE_MASK,gclink, + "Channel forcePV RESET <%s> [%s] [%s]", + buff1, + buff2, + pforcePV->name); + } + alCaFlushIo(); + } + } + pforcePV->currentValue=calcValue; +} + +/******************************************************************* + ForcePV Value Event from CA +*******************************************************************/ +void alForcePVValueEvent ( void* userdata,double value) { + FORCEPVCADATA* puser = (FORCEPVCADATA*)userdata; + GCLINK* gclink; + short index; + short linktype; + + if (!puser) return; + gclink=(GCLINK*)puser->link; + index=puser->index; + linktype=puser->linktype; + + if (puser->index==-1) forcePVNewValueEvent(gclink,linktype,value); + else alForcePVCalcNewValueEvent(gclink,linktype,index,value); +} diff --git a/guidance.c b/guidance.c new file mode 100644 index 0000000..7e86d32 --- /dev/null +++ b/guidance.c @@ -0,0 +1,112 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* guidance.c */ + +/************************DESCRIPTION*********************************** + This file contains routines for displaying guidance text +**********************************************************************/ + +#include <stdlib.h> +#include <Xm/Xm.h> + +#include "alLib.h" +#include "ax.h" + +/************************************************************************ + Guidance display callback + ***********************************************************************/ +void guidanceCallback(Widget w,GCLINK *gclink,XmAnyCallbackStruct *cbs) +{ + SNODE *pt; + struct guideLink *guidelist; + char *guidance_str[200]; + int i=0; + + if (guidanceExists(gclink)) { + if (gclink->guidanceLocation ) { + callBrowser(gclink->guidanceLocation); + } else { + pt = sllFirst(&(gclink->GuideList)); + i=0; + while (pt) { + guidelist = (struct guideLink *)pt; + guidance_str[i] = guidelist->list; + pt = sllNext(pt); + i++; + } + guidance_str[i] = ""; + guidance_str[i+1] = ""; + + xs_help_callback(w,guidance_str,cbs); + } + } + else { + if (gclink->pgcData->alias){ + createDialog(w,XmDIALOG_WARNING,"No guidance for ", + gclink->pgcData->alias); + } else { + createDialog(w,XmDIALOG_WARNING,"No guidance for ", + gclink->pgcData->name); + } + } +} + +/************************************************************************ + Guidance exists test + ***********************************************************************/ +int guidanceExists(GCLINK *link) +{ + if (sllFirst(&(link->GuideList)) || link->guidanceLocation) return(TRUE); + else return(FALSE); +} + +/************************************************************************ + Delete guidance + ***********************************************************************/ +void guidanceDeleteGuideList(SLIST *pGuideList) +{ + SNODE *node,*next; + struct guideLink *guidelist; + + node = sllFirst(pGuideList); + while (node) { + next = sllNext(node); + guidelist = (struct guideLink *)node; + free(guidelist->list); + free(guidelist); + node = next; + } +} + +/************************************************************************ + Copy guidance + ***********************************************************************/ +void guidanceCopyGuideList(SLIST *pToGuideList,SLIST *pFromGuideList) +{ + char *buff; + struct guideLink *guideLink; + SNODE *node; + + node = sllFirst(pFromGuideList); + while (node) { + buff = ((struct guideLink *)node)->list; + guideLink = (struct guideLink *)calloc(1,sizeof(struct guideLink)); + guideLink->list = (char *)calloc(1,strlen(buff)+1); + strcpy(guideLink->list,buff); + sllAdd(pToGuideList,(SNODE *)guideLink); + node = sllNext(node); + } +} + diff --git a/heartbeat.c b/heartbeat.c new file mode 100644 index 0000000..42e9c2c --- /dev/null +++ b/heartbeat.c @@ -0,0 +1,93 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* heartbeat.c */ + +/************************DESCRIPTION*********************************** + Routines for the config file heartbeat +**********************************************************************/ + +#include <stdlib.h> + +#include "ax.h" + +static void alHeartbeatTimerCallback(XtPointer data, XtIntervalId *id) +{ + struct mainGroup *pmainGroup = (struct mainGroup *)data; + + if (!pmainGroup) return; + if (!pmainGroup->heartbeatPV.chid) return; + alCaPutHeartbeatValue(pmainGroup->heartbeatPV.chid,&(pmainGroup->heartbeatPV.caputValue)); + + pmainGroup->heartbeatPV.timerId = XtAppAddTimeOut(appContext, + (unsigned long)(1000*pmainGroup->heartbeatPV.caputRateInSeconds), + (XtTimerCallbackProc)alHeartbeatTimerCallback, + (XtPointer)data); +} + +void alHeartbeatStart(void *data) +{ + struct mainGroup *pmainGroup = (struct mainGroup *)data; + + if (!pmainGroup) return; + if (pmainGroup->heartbeatPV.timerId) { + XtRemoveTimeOut(pmainGroup->heartbeatPV.timerId); + pmainGroup->heartbeatPV.timerId = 0; + } + + pmainGroup->heartbeatPV.timerId = XtAppAddTimeOut(appContext, + (unsigned long)(1000*pmainGroup->heartbeatPV.caputRateInSeconds), + (XtTimerCallbackProc)alHeartbeatTimerCallback, + (XtPointer)data); +} + + +void alHeartbeatStop(void *data) +{ + struct mainGroup *pmainGroup = (struct mainGroup *)data; + + if (!pmainGroup) return; + if (pmainGroup->heartbeatPV.timerId) { + XtRemoveTimeOut(pmainGroup->heartbeatPV.timerId); + pmainGroup->heartbeatPV.timerId = 0; + } +} + +void alHeartbeatPVRemove(struct mainGroup *pmainGroup) +{ + if (!pmainGroup) return; + if (pmainGroup->heartbeatPV.timerId) { + XtRemoveTimeOut(pmainGroup->heartbeatPV.timerId); + pmainGroup->heartbeatPV.timerId = 0; + } + if (pmainGroup->heartbeatPV.name) { + free(pmainGroup->heartbeatPV.name); + pmainGroup->heartbeatPV.name = 0; + } + if (pmainGroup->heartbeatPV.chid) { + alCaClearChannel(&(pmainGroup->heartbeatPV.chid)); + pmainGroup->heartbeatPV.chid = 0; + } +} + +void alHeartbeatPVAdd(struct mainGroup *pmainGroup,char* name,float rate,short value) +{ + if (!pmainGroup) return; + alHeartbeatPVRemove(pmainGroup); + pmainGroup->heartbeatPV.name = (char *)calloc(1,strlen(name)+1); + strcpy(pmainGroup->heartbeatPV.name,name); + pmainGroup->heartbeatPV.caputRateInSeconds = rate; + pmainGroup->heartbeatPV.caputValue = value; +} + diff --git a/help.c b/help.c new file mode 100644 index 0000000..7c5c90c --- /dev/null +++ b/help.c @@ -0,0 +1,216 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* help.h */ + +/************************DESCRIPTION*********************************** +*This files contains the *PUBLIC* routines for creating a +*dialog message box. The created message dialog consists +*a message text widget and two push buttons-- 'Ok', and +*'Help'. +* +*The presence of 'Help' button depends on the help textaul +*string array. A single null string corresponds to a 'Help' +*button and causes remaining text shown on next page. Two +*consecutive null strings indicates the end of help text. +**********************************************************************/ + +#include <stdlib.h> + +#include <X11/StringDefs.h> +#include <X11/Intrinsic.h> +#include <Xm/Xm.h> +#include <Xm/MessageB.h> +#include <Xm/PushB.h> +#include <Xm/CascadeB.h> +#include <Xm/RowColumn.h> + +/* WIN32 differences */ +#ifdef WIN32 +/* Needs to be included before XlibXtra.h for Exceed 5 */ +#include <stdio.h> +/* Hummingbird extra functions including lprintf + * Needs to be included after Intrinsic.h for Exceed 5 + * (Intrinsic.h is included in xtParams.h) */ +/*#include <X11/XlibXtra.h>*/ +/* This is done in Exceed 6 but not in Exceed 5 + * Need it to define printf as lprintf for Windows + * (as opposed to Console) apps */ +#ifdef _WINDOWS +#ifndef printf +#define printf lprintf +#endif +#endif +#endif /* #ifdef WIN32 */ + +#include "ax.h" + +/******************************************************* + delete an existing widget +*******************************************************/ +static void xs_ok_callback(Widget w,void *client_data, +XmAnyCallbackStruct *call_data) +{ + XtUnmanageChild(w); + XtDestroyWidget(w); +} + +/************************************************************* + * xs_str_array_to_xmstr() : convert char ** to + * compound string + ************************************************************/ +static XmString xs_str_array_to_xmstr(char *cs[],int n) +{ + XmString xmstr,xmsep, xmstr1,xmstr2 ; + int i; + /* + * if the array is empty just return an empty string. + */ + if (n <= 0) + return(XmStringCreate("",XmSTRING_DEFAULT_CHARSET)); + + xmstr = (XmString) NULL; + xmsep = XmStringSeparatorCreate(); + + for (i=0;i<n;i++) { + xmstr1=xmstr; + if (i > 0) xmstr = XmStringConcat(xmstr1,xmsep); + XmStringFree(xmstr1); + xmstr1 = xmstr; + xmstr2 = XmStringCreate(cs[i],XmSTRING_DEFAULT_CHARSET); + xmstr = XmStringConcat(xmstr1,xmstr2); + XmStringFree(xmstr1); + XmStringFree(xmstr2); + } + XmStringFree(xmsep); + return (xmstr); +} + +/************************************************************* + * the help button call back function from a dialog widget + ************************************************************/ +void xs_help_callback(Widget w,char *str[],void *call_data) +{ + int i,n; + Widget dialog; + XmString xmstr; + Arg wargs[5]; + char *title=NULL; + char *buff=NULL; + + /* + * Get the title name + */ + XtVaGetValues(w, XmNuserData, &title,NULL); + if (title){ + buff=(char *)calloc(1,strlen(title)+12); + strcpy(buff,title); + strcat(buff," Guidance"); + strcat(buff,"\0"); + } + + /* + * Create the message dialog to display the help. + */ + n=0; + if (buff){ + XtSetArg(wargs[n], XmNtitle, buff); + n++; + } + XtSetArg(wargs[n], XmNautoUnmanage, FALSE); + n++; + XtSetArg(wargs[n], XmNallowShellResize, FALSE); + n++; + dialog = XmCreateMessageDialog(w, "Help", wargs, n); + free(buff); + /* + * We won't use the cancel widget. Unmanage it. + */ + XtUnmanageChild(XmMessageBoxGetChild(dialog, + XmDIALOG_CANCEL_BUTTON)); + /* + * Retrieve the label widget and make the + * text left justified + */ + + /* + label = XmMessageBoxGetChild(dialog, + XmDIALOG_MESSAGE_LABEL); + + n = 0; + XtSetArg(wargs[n],XmNalignment,XmALIGNMENT_BEGINNING); n++; + XtSetValues(label, wargs, n); + */ + + /* + * Add an OK callback to pop down the dialog. + */ + XtAddCallback(dialog, XmNokCallback,(XtCallbackProc)xs_ok_callback, NULL); + + /* + * count the test up to the first NUll string. + */ + for (i=0;str[i][0] != '\0';i++) + ; + /* + * convert the string array to an XmString array and set it as the label text. + */ + + + xmstr = xs_str_array_to_xmstr(str,i); + + n = 0; + XtSetArg(wargs[n], XmNmessageString, xmstr); + n++; + XtSetValues(dialog, wargs, n); + + XmStringFree(xmstr); + + /* + * if the next entryu in the help string array is also NULL, + * then this is the last message. Unmanage the help button. + */ + + if (str[++i][0] == '\0') + XtUnmanageChild( XmMessageBoxGetChild(dialog, + XmDIALOG_HELP_BUTTON)); + + /* + * otherwise add a help callback function with the address of + * the next entryu in the help string as client_data. + */ + + else { + XtAddCallback(dialog, XmNhelpCallback, + (XtCallbackProc)xs_help_callback, &str[i]); + + } + + /* + * display the dialog. + */ + XtManageChild(dialog); + +} + + +/****************************************************** + helpCallback +******************************************************/ +void helpCallback(Widget widget,int item,XmAnyCallbackStruct *cbs) +{ + createDialog(widget,XmDIALOG_INFORMATION, + "Help is not available in this release."," "); +} + diff --git a/line.c b/line.c new file mode 100644 index 0000000..392391c --- /dev/null +++ b/line.c @@ -0,0 +1,178 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* line.c */ + +/************************DESCRIPTION*********************************** + Routines for alloc, init, and update of a displayed line +**********************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +#include "alarm.h" + +#include "alh.h" +#include "alLib.h" +#include "sllLib.h" +#include "axSubW.h" +#include "line.h" +#include "axArea.h" +#include "ax.h" + +/* global variables */ +extern char * alhAlarmSeverityString[]; +extern char * alhAlarmStatusString[]; +extern char *bg_char[]; + +static char buff[LINEMESSAGE_SIZE]; + +/********************************************************************* + * This function returns a string with 5 characters which shows + * the group mask. The input to this function is the group + * mask array. + *********************************************************************/ +void awGetMaskString(int mask[ALARM_NMASK],char *s) +{ + strcpy(s,"-----"); + if (mask[ALARMCANCEL] > 0) *s = 'C'; + if (mask[ALARMDISABLE] > 0) *(s+1) = 'D'; + if (mask[ALARMACK] > 0) *(s+2) = 'A'; + if (mask[ALARMACKT] > 0) *(s+3) = 'T'; + if (mask[ALARMLOG] > 0) *(s+4) = 'L'; + *(s+5) = '\0'; +} + +/********************************************************************* + * This function allocates space for new line + *********************************************************************/ +struct anyLine *awAllocLine() +{ + struct anyLine *pLine; + pLine = (struct anyLine *)calloc(1,sizeof(struct anyLine)); + return(pLine); +} + +/********************************************************************* + * This function updates the channel line mask , status & severity + *********************************************************************/ +void awUpdateChanLine(struct anyLine *chanLine) +{ + struct chanData *cdata; + CLINK *clink; + + clink = (CLINK *)chanLine->link; + if (!clink) return; + cdata = clink->pchanData; + chanLine->unackSevr = cdata->unackSevr; + chanLine->curSevr = cdata->curSevr; + chanLine->curStat = cdata->curStat; + + if (cdata->curMask.Disable == MASK_ON || + cdata->curMask.Cancel == MASK_ON) { + chanLine->curSevr = 0; + chanLine->unackSevr = 0; + } + if (cdata->curMask.Ack == MASK_ON) { + chanLine->unackSevr = 0; + } + alGetMaskString(cdata->curMask,buff); + if (cdata->noAckTimerId ) buff[2]='H'; + sprintf(chanLine->mask,"<%s>",buff); + + strcpy(chanLine->message," "); + + if (!cdata->curMask.Disable && !cdata->curMask.Cancel && + (cdata->curSevr || cdata->unackSevr)){ + + sprintf(chanLine->message,"<%s,%s>", + alhAlarmStatusString[cdata->curStat], + alhAlarmSeverityString[cdata->curSevr]); + + if (cdata->unackSevr){ + sprintf(buff,",<%s>", + alhAlarmSeverityString[cdata->unackSevr]); + strcat(chanLine->message,buff); + } + } + if(cdata->highestBeepSevr>1) strcpy(chanLine->highestBeepSevrString, + bg_char[cdata->highestBeepSevr]); + else strcpy(chanLine->highestBeepSevrString," "); +} + +/*************************************************************************** + * This function updates the group line mask , status & severity, summary + ***************************************************************************/ +void awUpdateGroupLine(struct anyLine *groupLine) +{ + struct groupData *gdata; + GLINK *glink; + int i; + + glink = (GLINK *)groupLine->link; + if (!glink) return; + gdata = glink->pgroupData; + awGetMaskString(gdata->mask,buff); + if (gdata->noAckTimerId ) buff[2]='H'; + sprintf(groupLine->mask,"<%s>",buff); + for (i=0;i<ALH_ALARM_NSEV;i++){ + groupLine->curSev[i] = gdata->curSev[i]; + } + groupLine->unackSevr = alHighestSeverity(gdata->unackSev); + groupLine->curSevr = alHighestSeverity(gdata->curSev); + + strcpy(groupLine->message," "); + + if (groupLine->unackSevr || alHighestSeverity(gdata->curSev)){ + sprintf(groupLine->message,"(%d,%d,%d,%d,%d)", + gdata->curSev[ERROR_STATE], + gdata->curSev[INVALID_ALARM], + gdata->curSev[MAJOR_ALARM], + gdata->curSev[MINOR_ALARM], + gdata->curSev[NO_ALARM]); + } + if(gdata->highestBeepSevr>1) strcpy(groupLine->highestBeepSevrString, + bg_char[gdata->highestBeepSevr]); + else strcpy(groupLine->highestBeepSevrString," "); +} + +/*************************************************** + Initializes all line fields +****************************************************/ +void initLine(struct anyLine *line) +{ + line->link = NULL; + line->cosCallback = NULL; + line->linkType = 0; + line->unackSevr = 0; + line->curSevr = 0; + line->pname = 0; + line->alias = 0; +} + +/*************************************************** + Initializes all subWindow lines +****************************************************/ +void initializeLines(SNODE *lines) +{ + struct anyLine *line; + + line = (struct anyLine *)sllFirst(lines); + while (line){ + initLine(line); + line = (struct anyLine *)sllNext(line); + } + +} + diff --git a/line.h b/line.h new file mode 100644 index 0000000..c83b1ee --- /dev/null +++ b/line.h @@ -0,0 +1,68 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* line.h */ + +/************************DESCRIPTION*********************************** + structure for displayed lines in the subWindows +**********************************************************************/ + +#ifndef INClineh +#define INClineh + +#include "sllLib.h" +#include "alh.h" + +#define LINEMESSAGE_SIZE 60 /* window message line size */ + +typedef void (*FUNPTR)(); /* define void function pointer */ + +/* group/channel Line data structure */ +struct anyLine { + SNODE node; /* line node type */ + int lineNo; /* line no in window */ + char mask[8]; /* mask summary string */ + char *pname; /* line name pointer */ + char *alias; /* line alias pointer */ + void *pwindow; /* corresponding window pointer */ + void *link; /* corresponding glink address */ + FUNPTR cosCallback; /* COS callback pointer */ + char message[LINEMESSAGE_SIZE]; /* summary message string */ + void *wline; /* address of line_widget */ + int linkType; /* type of gclink group or channel */ + short curSevr; /* current severity */ + short unackSevr; /* highest unack severity */ + char highestBeepSevrString[2]; /* highest beep severity */ + int curStat; /* Channel: current status */ + int curSev[ALH_ALARM_NSEV]; /* Group: current sevr channel counts*/ +}; + +struct widgetLine { + Widget row_widget; + Widget treeSym; + Widget ack; + Widget sevr; + Widget name; + Widget arrow; + Widget guidance; + Widget process; + Widget mask; + Widget message; + Widget highestbeepsevr; +}; + +typedef struct widgetLine WLINE; + +#endif /* INClineh */ + diff --git a/mask.c b/mask.c new file mode 100644 index 0000000..6a90c0e --- /dev/null +++ b/mask.c @@ -0,0 +1,403 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* mask.c */ + +/************************DESCRIPTION*********************************** + This file contains routines for modifying masks +**********************************************************************/ + +#include <stdlib.h> + +#include <Xm/Xm.h> +#include <Xm/Form.h> +#include <Xm/Frame.h> +#include <Xm/LabelG.h> +#include <Xm/PushB.h> +#include <Xm/ToggleB.h> +#include <Xm/PanedW.h> +#include <Xm/Protocols.h> +#include <Xm/RowColumn.h> +#include <Xm/ToggleBG.h> + +#include "axArea.h" +#include "alLib.h" +#include "alh.h" +#include "ax.h" + +extern int _passive_flag; +extern const char *masksdata[]; +extern const char *mask_str[]; + +typedef struct { + char *label; + int index; +} maskChoiceItem; + +typedef struct { + char *label; + maskChoiceItem choice[3]; +} maskItem; + +struct maskWindow { + void *area; + Widget menuButton; + Widget maskDialog; + Widget nameLabelW; + Widget nameTextW; +}; + +/* forward declarations */ +static void maskDismissCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void maskHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void maskActivateCallback( Widget widget,XtPointer calldata,XtPointer cbs); +static void maskCreateDialog(ALINK*area); +static void maskUpdateDialogWidgets(struct maskWindow *maskWindow); + + +/****************************************************** + maskUpdateDialog +******************************************************/ +void maskUpdateDialog(ALINK *area) +{ + struct maskWindow *maskWindow; + + maskWindow = (struct maskWindow *)area->maskWindow; + + if (!maskWindow) return; + + if (!maskWindow->maskDialog || + !XtIsManaged(maskWindow->maskDialog)) return; + + maskUpdateDialogWidgets(maskWindow); +} + +/****************************************************** + maskShowDialog +******************************************************/ +void maskShowDialog(ALINK *area,Widget menuButton) +{ + struct maskWindow *maskWindow; + + maskWindow = (struct maskWindow *)area->maskWindow; + + /* dismiss Dialog */ + if (maskWindow && maskWindow->maskDialog && + XtIsManaged(maskWindow->maskDialog)) { + maskDismissCallback(NULL, (XtPointer)maskWindow, NULL); + return; + } + + /* create maskWindow and Dialog Widgets if necessary */ + if (!maskWindow) maskCreateDialog(area); + + /* update maskWindow */ + maskWindow = (struct maskWindow *)area->maskWindow; + maskWindow->menuButton = menuButton; + + /* update Dialog Widgets */ + maskUpdateDialogWidgets(maskWindow); + + /* show Dialog */ + if (!maskWindow->maskDialog) return; + if (!XtIsManaged(maskWindow->maskDialog)) { + XtManageChild(maskWindow->maskDialog); + } + XMapWindow(XtDisplay(maskWindow->maskDialog), + XtWindow(XtParent(maskWindow->maskDialog))); + if (menuButton) XtVaSetValues(menuButton, XmNset, TRUE, NULL); +} + +/****************************************************** + maskUpdateDialogWidgets +******************************************************/ +static void maskUpdateDialogWidgets(struct maskWindow *maskWindow) +{ + struct gcData *pgcData; + GCLINK *link; + int linkType; + XmString string; + + if (! maskWindow || !maskWindow->maskDialog ) return; + + link =getSelectionLinkArea(maskWindow->area); + + if (!link) { + string = XmStringCreateSimple(""); + if (maskWindow->nameTextW ) + XtVaSetValues(maskWindow->nameTextW,XmNlabelString, string, NULL); + XmStringFree(string); + return; + } + + pgcData = link->pgcData; + linkType =getSelectionLinkTypeArea(maskWindow->area); + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + if (linkType == GROUP) string = XmStringCreateSimple("Group Name:"); + else string = XmStringCreateSimple("Channel Name:"); + XtVaSetValues(maskWindow->nameLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + + if (pgcData->alias){ + string = XmStringCreateSimple(pgcData->alias); + } else { + string = XmStringCreateSimple(pgcData->name); + } + XtVaSetValues(maskWindow->nameTextW, XmNlabelString, string, NULL); + XmStringFree(string); +} + +/****************************************************** + maskCreateDialog +******************************************************/ +static void maskCreateDialog(ALINK *area) +{ + struct maskWindow *maskWindow; + + Widget maskDialogShell, maskDialog; + Widget form; + Widget nameLabelW, nameTextW; + Widget labelW, pushButtonW, prev; + int i,j; + static ActionAreaItem buttonItems[] = { + { "Dismiss", maskDismissCallback, NULL }, + { "Help", maskHelpCallback, NULL }, + }; + static maskItem maskItem[] = { + { "Add/Cancel Alarms", {{"Add", 0},{"Cancel", 1},{"Reset", 2}}}, + { "Enable/Disable Alarms", {{"Enable",10},{"Disable",11},{"Reset",12}}}, + { "Ack/NoAck Alarms", {{"Ack", 20},{"NoAck", 21},{"Reset",22}}}, + { "Ack/NoAck Transient Alarms",{{"AckT", 30},{"NoAckT", 31},{"Reset",32}}}, + { "Log/NoLog Alarms", {{"Log", 40},{"NoLog", 41},{"Reset",42}}}, + }; + int num_buttons = 3; + int num_rows = 5; + + if (!area) return; + + maskWindow = (struct maskWindow *)area->maskWindow; + + if (maskWindow && maskWindow->maskDialog){ + if (XtIsManaged(maskWindow->maskDialog)) return; + else XtManageChild(maskWindow->maskDialog); + } + + maskWindow = (struct maskWindow *)calloc(1,sizeof(struct maskWindow)); + area->maskWindow = (void *)maskWindow; + maskWindow->area = (void *)area; + + maskDialogShell = XtVaCreatePopupShell("Modify Mask Settings", + transientShellWidgetClass, area->toplevel, + XmNallowShellResize, TRUE, + NULL); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(maskDialogShell, + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(maskDialogShell), + "WM_DELETE_WINDOW", False); + XmAddWMProtocolCallback(maskDialogShell,WM_DELETE_WINDOW, + (XtCallbackProc)maskDismissCallback, (XtPointer)maskWindow); + } + + maskDialog = XtVaCreateWidget("maskDialog", + xmPanedWindowWidgetClass, maskDialogShell, + XmNallowResize, TRUE, + XmNsashWidth, 1, + XmNsashHeight, 1, + XmNuserData, area, + NULL); + + form = XtVaCreateWidget("control_area", + xmFormWidgetClass, maskDialog, + XmNfractionBase, TIGHTNESS*(num_buttons+3) - 1, + XmNallowResize, TRUE, + NULL); + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + nameLabelW = XtVaCreateManagedWidget("nameLabelW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_END, + XmNtopAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, (TIGHTNESS*(num_buttons+3) - 1)/2, + XmNrecomputeSize, True, + (XtPointer)NULL); + + nameTextW = XtVaCreateManagedWidget("nameTextW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, nameLabelW, + XmNrightAttachment, XmATTACH_NONE, + XmNrecomputeSize, True, + NULL); + + + prev = nameLabelW; + for (i = 0; i < num_rows; i++){ + labelW = XtVaCreateManagedWidget(maskItem[i].label, + xmLabelGadgetClass, form, + XmNleftAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNtopOffset, 10, + NULL); + for (j = 0; j < num_buttons; j++){ + pushButtonW = XtVaCreateManagedWidget( + maskItem[i].choice[j].label, + xmPushButtonWidgetClass, form, + XmNuserData, (XtPointer)area, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, TIGHTNESS*(j+3), + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNtopOffset, 5, + XmNrightAttachment, + j != num_buttons-1? XmATTACH_POSITION : XmATTACH_FORM, + XmNrightPosition, TIGHTNESS*(j+3) + (TIGHTNESS-1), + NULL); + long index=maskItem[i].choice[j].index; + XtAddCallback(pushButtonW, XmNactivateCallback, + (XtCallbackProc)maskActivateCallback, + (XtPointer)index); + if (_passive_flag && i == ALARMACKT ) { /* ACKT */ + XtVaSetValues(pushButtonW, XmNsensitive, FALSE, NULL); + } + } + prev=labelW; + } + + XtManageChild(form); + + /* Set the client data "Dismiss" and "Help" button's callbacks. */ + buttonItems[0].data = (XtPointer)maskWindow; + buttonItems[1].data = (XtPointer)maskWindow; + + (void)createActionButtons(maskDialog, buttonItems, XtNumber(buttonItems)); + + XtManageChild(maskDialog); + + maskWindow->maskDialog = maskDialog; + maskWindow->nameLabelW = nameLabelW; + maskWindow->nameTextW = nameTextW; + + XtRealizeWidget(maskDialogShell); +} + +/****************************************************** + maskHelpCallback +******************************************************/ +static void maskHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + char *message1 = + "This dialog window allows an operator" + " to change individual mask field\n" + "values for a group or channel.\n" + "Changing a mask field value for a group" + " means changing the mask field\n" + "value for all channels in the group.\n" + " \n" + "Changing Ack/NoAck Transient Alarms is " + "not allowed when executing in passive state " + " \n\n" + "Press the Dismiss button to close the" + " Modify Mask Settings dialog window.\n" + "Press the Help button to get this help description window.\n" + ; + char * message2 = " "; + + createDialog(widget,XmDIALOG_INFORMATION, message1,message2); + +} + + +/****************************************************** + maskDismissCallback +******************************************************/ +static void maskDismissCallback(Widget widget,XtPointer calldata, +XtPointer cbs) +{ + struct maskWindow *maskWindow=(struct maskWindow *)calldata; + Widget maskDialog; + + maskDialog = maskWindow->maskDialog; + XtUnmanageChild(maskDialog); + XUnmapWindow(XtDisplay(maskDialog), XtWindow(XtParent(maskDialog))); + if (maskWindow->menuButton) + XtVaSetValues(maskWindow->menuButton, XmNset, FALSE, NULL); +} + +/*************************************************** + maskActivateCallback +****************************************************/ +static void maskActivateCallback(Widget widget,XtPointer calldata, +XtPointer cbs) +{ + int index=(long)calldata; + ALINK *area; + void *link; + int maskid,maskno; + int linkType; + char buff1[6]; + + maskid = index/ 10; + maskno = index % 10; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + link =getSelectionLinkArea(area); + + /* Change mask */ + if (link){ + linkType =getSelectionLinkTypeArea(area); + if (linkType == GROUP){ + if (maskid == ALARMACK) alRemoveNoAck1HrTimerGroup(link); + alForceGroupMask(link,maskid,maskno); + awGetMaskString(((GLINK*)link)->pgroupData->mask,buff1); + alLogOpModMessage(CHANGE_MASK,(GCLINK*)link, + "Group Mask [%s] %s <%s>", + masksdata[maskid], + mask_str[maskno], + buff1); + } else { + if (maskid == ALARMACK) alRemoveNoAck1HrTimerChan(link); + alForceChanMask(link,maskid,maskno); + + alGetMaskString(((CLINK*)link)->pchanData->curMask,buff1); + alLogOpModMessage(CHANGE_MASK,(GCLINK*)link, + "Channel Mask [%s] %s <%s>", + masksdata[maskid], + mask_str[maskno], + buff1); + } + silenceCurrentReset(area); + } else { + createDialog(widget,XmDIALOG_WARNING, + "Please select an alarm group or channel first."," "); + } + + /* --------------------------------- + Update all dialog Windows + --------------------------------- */ + axUpdateDialogs(area); + +} + diff --git a/noAck.c b/noAck.c new file mode 100644 index 0000000..0b901c5 --- /dev/null +++ b/noAck.c @@ -0,0 +1,454 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* noAck.c */ + +/************************DESCRIPTION*********************************** + Routines for modifying noAck mask for 1 hour. +**********************************************************************/ + +#include <stdlib.h> + +#include <Xm/Xm.h> +#include <Xm/Form.h> +#include <Xm/Frame.h> +#include <Xm/LabelG.h> +#include <Xm/PushB.h> +#include <Xm/ToggleB.h> +#include <Xm/PanedW.h> +#include <Xm/Protocols.h> +#include <Xm/RowColumn.h> +#include <Xm/ToggleBG.h> + +#include "axArea.h" +#include "alLib.h" +#include "alh.h" +#include "ax.h" + +extern int _DB_call_flag; + +typedef struct { + char *label; + int index; +} noAckChoiceItem; + +struct noAckWindow { + void *area; + Widget menuButton; + Widget noAckDialog; + Widget nameLabelW; + Widget nameTextW; + Widget noAckOneHourToggleButton; +}; + +/* forward declarations */ +static void noAckDismissCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void noAckHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void noAckActivateCallback( Widget widget,XtPointer calldata,XtPointer cbs); +static void noAckCreateDialog(ALINK*area); +static void noAckUpdateDialogWidgets(struct noAckWindow *noAckWindow); +static void noAckOneHourTimerGroupCallback(XtPointer data, XtIntervalId *id); +static void noAckOneHourTimerChanCallback(XtPointer data, XtIntervalId *id); +static void alResetNoAckChan(CLINK *clink); +static void alResetNoAckGroup(GLINK *glink); + +/****************************************************** + noAckUpdateDialog +******************************************************/ +void noAckUpdateDialog(ALINK *area) +{ + struct noAckWindow *noAckWindow; + + noAckWindow = (struct noAckWindow *)area->noAckWindow; + + if (!noAckWindow) return; + + if (!noAckWindow->noAckDialog || + !XtIsManaged(noAckWindow->noAckDialog)) return; + + noAckUpdateDialogWidgets(noAckWindow); +} + +/****************************************************** + noAckShowDialog +******************************************************/ +void noAckShowDialog(ALINK *area,Widget menuButton) +{ + struct noAckWindow *noAckWindow; + + noAckWindow = (struct noAckWindow *)area->noAckWindow; + + /* dismiss Dialog */ + if (noAckWindow && noAckWindow->noAckDialog && + XtIsManaged(noAckWindow->noAckDialog)) { + noAckDismissCallback(NULL, (XtPointer)noAckWindow, NULL); + return; + } + + /* create noAckWindow and Dialog Widgets if necessary */ + if (!noAckWindow) noAckCreateDialog(area); + + /* update noAckWindow */ + noAckWindow = (struct noAckWindow *)area->noAckWindow; + noAckWindow->menuButton = menuButton; + + /* update Dialog Widgets */ + noAckUpdateDialogWidgets(noAckWindow); + + /* show Dialog */ + if (!noAckWindow->noAckDialog) return; + if (!XtIsManaged(noAckWindow->noAckDialog)) { + XtManageChild(noAckWindow->noAckDialog); + } + XMapWindow(XtDisplay(noAckWindow->noAckDialog), + XtWindow(XtParent(noAckWindow->noAckDialog))); + if (menuButton) XtVaSetValues(menuButton, XmNset, TRUE, NULL); +} + +/****************************************************** + noAckUpdateDialogWidgets +******************************************************/ +static void noAckUpdateDialogWidgets(struct noAckWindow *noAckWindow) +{ + struct gcData *pgcData; + GCLINK *link; + int linkType; + XmString string; + + if (! noAckWindow || !noAckWindow->noAckDialog ) return; + + link =getSelectionLinkArea(noAckWindow->area); + + /* --------------------------------- + Group/Channel name + --------------------------------- */ + if (!link) { + string = XmStringCreateSimple(""); + if (noAckWindow->nameTextW ) + XtVaSetValues(noAckWindow->nameTextW,XmNlabelString, string, NULL); + XmStringFree(string); + return; + } + + pgcData = link->pgcData; + linkType =getSelectionLinkTypeArea(noAckWindow->area); + + /* --------------------------------- + Group/Channel label + --------------------------------- */ + if (linkType == GROUP) string = XmStringCreateSimple("Group: "); + else string = XmStringCreateSimple("Channel: "); + XtVaSetValues(noAckWindow->nameLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + + if (pgcData->alias){ + string = XmStringCreateSimple(pgcData->alias); + } else { + string = XmStringCreateSimple(pgcData->name); + } + XtVaSetValues(noAckWindow->nameTextW, XmNlabelString, string, NULL); + XmStringFree(string); + + /* --------------------------------- + noAck for one hour toggle button + --------------------------------- */ + if (pgcData->noAckTimerId) + XmToggleButtonGadgetSetState(noAckWindow->noAckOneHourToggleButton,TRUE,FALSE); + else XmToggleButtonGadgetSetState(noAckWindow->noAckOneHourToggleButton,FALSE,FALSE); +} + +/****************************************************** + noAckCreateDialog +******************************************************/ +static void noAckCreateDialog(ALINK *area) +{ + struct noAckWindow *noAckWindow; + + Widget noAckDialogShell, noAckDialog; + Widget form; + Widget nameLabelW, nameTextW; + Widget noAckOneHourToggleButton; + static ActionAreaItem buttonItems[] = { + { "Dismiss", noAckDismissCallback, NULL }, + { "Help", noAckHelpCallback, NULL }, + }; + + if (!area) return; + + noAckWindow = (struct noAckWindow *)area->noAckWindow; + + if (noAckWindow && noAckWindow->noAckDialog){ + if (XtIsManaged(noAckWindow->noAckDialog)) return; + else XtManageChild(noAckWindow->noAckDialog); + } + + noAckWindow = (struct noAckWindow *)calloc(1,sizeof(struct noAckWindow)); + area->noAckWindow = (void *)noAckWindow; + noAckWindow->area = (void *)area; + + noAckDialogShell = XtVaCreatePopupShell("Modify NoAck Mask", + transientShellWidgetClass, area->toplevel, + XmNallowShellResize, TRUE, + NULL); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(noAckDialogShell, + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(noAckDialogShell), + "WM_DELETE_WINDOW", False); + XmAddWMProtocolCallback(noAckDialogShell,WM_DELETE_WINDOW, + (XtCallbackProc)noAckDismissCallback, (XtPointer)noAckWindow); + } + + noAckDialog = XtVaCreateWidget("noAckDialog", + xmPanedWindowWidgetClass, noAckDialogShell, + XmNallowResize, TRUE, + XmNsashWidth, 1, + XmNsashHeight, 1, + XmNuserData, area, + (XtPointer)NULL); + + form = XtVaCreateWidget("control_area", + xmFormWidgetClass, noAckDialog, + XmNallowResize, TRUE, + NULL); + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + nameLabelW = XtVaCreateManagedWidget("nameLabelW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_END, + XmNtopAttachment, XmATTACH_FORM, + XmNrecomputeSize, True, + NULL); + + nameTextW = XtVaCreateManagedWidget("nameTextW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, nameLabelW, + XmNrightAttachment, XmATTACH_NONE, + XmNrecomputeSize, True, + NULL); + + /* --------------------------------- + NoAck One Hour toggle button + --------------------------------- */ + noAckOneHourToggleButton = XtVaCreateManagedWidget("NoAck For One Hour", + xmToggleButtonGadgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, nameLabelW, + XmNtopOffset, 10, + XmNuserData, (XtPointer)area, + NULL); + + XtAddCallback(noAckOneHourToggleButton, XmNvalueChangedCallback, + (XtCallbackProc)noAckActivateCallback,area); + + XtManageChild(form); + + /* Set the client data "Dismiss" and "Help" button's callbacks. */ + buttonItems[0].data = (XtPointer)noAckWindow; + buttonItems[1].data = (XtPointer)noAckWindow; + + (void)createActionButtons(noAckDialog, buttonItems, XtNumber(buttonItems)); + + noAckWindow->noAckDialog = noAckDialog; + noAckWindow->nameLabelW = nameLabelW; + noAckWindow->nameTextW = nameTextW; + noAckWindow->noAckOneHourToggleButton = noAckOneHourToggleButton; + + XtManageChild(noAckDialog); + + XtRealizeWidget(noAckDialogShell); +} + +/****************************************************** + noAckHelpCallback +******************************************************/ +static void noAckHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + char *message1 = + "Set group or channel ack/noAck mask to noAck for one hour and then\n" + "reset it to initial (config file) value after the hour is over.\n\n" + "Setting the 'noAck for One Hour' button to ON means setting the ack/noAck\n" + "mask to noAck for the selected channel or for all channels in the\n" + "selected group and creating a one hour timer. When the timer expires\n" + "the ack/noAck masks will be set to the initial value from the config file.\n\n" + ; + char * message2 = + "Setting the 'noAck for One Hour' button to OFF means setting the ack/noAck\n" + "mask to the initial value from the config file for the celected channel or\n" + "for all channels in the selected group and removing the one hour timer.\n\n" + "Press the Dismiss button to close the dialog window.\n" + "Press the Help button to get this help description window.\n" + ; + + createDialog(widget,XmDIALOG_INFORMATION, message1,message2); + +} + + +/****************************************************** + noAckDismissCallback +******************************************************/ +static void noAckDismissCallback(Widget widget,XtPointer calldata, +XtPointer cbs) +{ + struct noAckWindow *noAckWindow=(struct noAckWindow *)calldata; + Widget noAckDialog; + + noAckDialog = noAckWindow->noAckDialog; + XtUnmanageChild(noAckDialog); + XUnmapWindow(XtDisplay(noAckDialog), XtWindow(XtParent(noAckDialog))); + if (noAckWindow->menuButton) + XtVaSetValues(noAckWindow->menuButton, XmNset, FALSE, NULL); +} + + +/*************************************************** + noAckOneHourTimerChanCallback +****************************************************/ +static void noAckOneHourTimerChanCallback(XtPointer data, XtIntervalId *id) +{ + CLINK * clink = (CLINK *)data; + + clink->pchanData->noAckTimerId=0;; + alResetNoAckChan(clink); + alLogOpModMessage(0,(GCLINK*)clink, + "Set Ack after expiration of NoAck one hour timer"); + clink->pmainGroup->modified = TRUE; + axUpdateDialogs(clink->pmainGroup->area); +} + +/*************************************************** + noAckOneHourTimerGroupCallback +****************************************************/ +static void noAckOneHourTimerGroupCallback(XtPointer data, XtIntervalId *id) +{ + GLINK * glink = (GLINK *)data; + + glink->pgroupData->noAckTimerId=0;; + alResetNoAckGroup(glink); + alLogOpModMessage(0,(GCLINK*)glink, + "Set Ack after expiration of NoAck one hour timer"); + glink->pmainGroup->modified = TRUE; + axUpdateDialogs(glink->pmainGroup->area); +} + +/*************************************************** + noAckActivateCallback +****************************************************/ +static void noAckActivateCallback(Widget widget,XtPointer link, +XtPointer call_data) +{ + int seconds = 3600; /* 1 hour */ +#if 0 + int seconds = 60; /* 1 minute */ +#endif + ALINK *area; + GCLINK *gclink; + struct gcData *gcdata; + int linkType; + XtTimerCallbackProc proc; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + gclink =(GCLINK *)getSelectionLinkArea(area); + gcdata = gclink->pgcData; + linkType =getSelectionLinkTypeArea(area); + if (linkType == GROUP) proc = noAckOneHourTimerGroupCallback; + else proc = noAckOneHourTimerChanCallback; + + if (gcdata->noAckTimerId) { + XtRemoveTimeOut(gcdata->noAckTimerId); + gcdata->noAckTimerId = 0; + } + if (XmToggleButtonGadgetGetState(widget)) { + if (linkType==GROUP) { + alRemoveNoAck1HrTimerGroup((GLINK*)gclink); + alForceGroupMask((GLINK*)gclink,ALARMACK,1); + } else { + alRemoveNoAck1HrTimerChan((CLINK*)gclink); + alForceChanMask((CLINK*)gclink,ALARMACK,1); + } + gcdata->noAckTimerId = XtAppAddTimeOut(appContext, + (unsigned long)(1000*seconds), + (XtTimerCallbackProc)proc, + (XtPointer)gclink); + alLogOpModMessage(0,gclink, + "Set NoAck and start NoAck one hour timer"); + } else { + if (linkType==GROUP) { + alResetNoAckGroup((GLINK *)gclink); + } else { + alResetNoAckChan((CLINK *)gclink); + } + alLogOpModMessage(0,gclink, + "Reset Ack mask and cancel NoAck one hour timer"); + } + gclink->modified = 1; + gclink->pmainGroup->modified = 1; + axUpdateDialogs(area); +} + + +/************************************************************************* + alResetNoAckChan + **********************************************************************/ +static void alResetNoAckChan(CLINK *clink) +{ + MASK mask; + + if (clink->pchanData->noAckTimerId) return; + + mask = clink->pchanData->curMask; + mask.Ack = clink->pchanData->defaultMask.Ack; + alChangeChanMask(clink,mask); + if(_DB_call_flag) alLog2DBMask(clink->pchanData->name); +} + +/************************************************************************* + alResetNoAckGroup + **********************************************************************/ +static void alResetNoAckGroup(GLINK *glink) +{ + GLINK *group; + CLINK *clink; + SNODE *pt; + + if (glink->pgroupData->noAckTimerId) return; + + /* + * for all channels in this group + */ + pt = sllFirst(&(glink->chanList)); + while (pt) { + clink = (CLINK *)pt; + alResetNoAckChan(clink); + pt = sllNext(pt); + } + /* + * for all subgroups + */ + pt = sllFirst(&(glink->subGroupList)); + while (pt) { + group = (GLINK *)pt; + alResetNoAckGroup(group); + pt = sllNext(pt); + } +} + diff --git a/os/WIN32/alAudio.c b/os/WIN32/alAudio.c new file mode 100644 index 0000000..e8095b3 --- /dev/null +++ b/os/WIN32/alAudio.c @@ -0,0 +1,607 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alAudio.c + * + alAudio.c,v 1.2 2002/08/02 15:37:47 jba Exp +*/ + +/************************DESCRIPTION*********************************** + Routines for audio output +**********************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> + +#include <windows.h> +#include <mmsystem.h> + +#include <Xm/Xm.h> +#include <Xm/AtomMgr.h> +#include <Xm/Form.h> +#include <Xm/Frame.h> +#include <Xm/LabelG.h> +#include <Xm/PanedW.h> +#include <Xm/Protocols.h> +#include <Xm/PushB.h> +#include <Xm/TextF.h> +#include <Xm/ToggleB.h> +#include <Xm/ToggleBG.h> +#include <Xm/Scale.h> + +#include "alAudio.h" +#include "ax.h" +#include "beep.h" + +#define AUDIO_INTERNAL_SPEAKER 0 +#define AUDIO_DEFAULT_OUTPUT 1 + +#define BEEP_AUDIO_SOURCE_INTERNAL 0 +#define BEEP_AUDIO_SOURCE_FILE 1 + +#define AUDIO_CHANNELS_MONO 1 +#define AUDIO_CHANNELS_STEREO 2 + +#define AUDIO_MAX_GAIN 0xFF +#define AUDIO_MID_GAIN 0x6F +#define AUDIO_MIN_GAIN 0x00 + +#define WAV_PATTERN "*.wav" + +extern Pixel bg_pixel[ALH_ALARM_NSEV]; + +static struct beepsetup { + Widget audioSetupDialog; + Widget beepSourceFrameWidget; + short port; + short channels; + short sampleRate; + short balance; + short beepSource; + unsigned char *beep; + unsigned long beepLength; + char *beepFileName; + unsigned char *beepFileData; + unsigned long beepFileLength; +} audioSetup={NULL,NULL,AUDIO_DEFAULT_OUTPUT,AUDIO_CHANNELS_STEREO, + 8000,50,BEEP_AUDIO_SOURCE_INTERNAL,0,0,0,0,0} ; + +/* forward declarations */ +static int audioSetupNewFilename(Widget textfield, char *filename); +static void audioSetupCreateDialog(Widget menuButton); +static void audioSetupDismissCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupOutputChangeCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupBeepSourceChangeCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupTestBeepCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupFilenameChangeCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupFilenameBrowseCallback( Widget widget,XtPointer clientdata, XtPointer cbs); + + +/****************************************************** + alhAudioSetupCallback +******************************************************/ +void alhAudioSetupCallback( Widget menuButton, XtPointer clientdata, +XtPointer cbs) +{ + /* dismiss the dialog */ + if (audioSetup.audioSetupDialog && + XtIsManaged(audioSetup.audioSetupDialog)) { + audioSetupDismissCallback(audioSetup.audioSetupDialog, + (XtPointer)menuButton, NULL); + if (menuButton) XtVaSetValues(menuButton, XmNset, FALSE, NULL); + return; + } + + /* create audioSetupWindow and Dialog Widgets if necessary */ + if (!audioSetup.audioSetupDialog) audioSetupCreateDialog(menuButton); + + /* show Dialog */ + if (!audioSetup.audioSetupDialog) return; + if (!XtIsManaged(audioSetup.audioSetupDialog)){ + XtManageChild(audioSetup.audioSetupDialog); + } + + XMapWindow(XtDisplay(audioSetup.audioSetupDialog), + XtWindow(XtParent(audioSetup.audioSetupDialog))); + + if (menuButton) XtVaSetValues(menuButton, XmNset, TRUE, NULL); +} + +/****************************************************** + alAudioBeep +******************************************************/ +static int alAudioBeep() +{ + if ( audioSetup.beep==0 && + audioSetup.beepSource == BEEP_AUDIO_SOURCE_INTERNAL) { + audioSetup.beep = beep; + audioSetup.beepLength = beepLength; + } + + if ( audioSetup.beep==0 ){ + if (audioSetup.beepSource==BEEP_AUDIO_SOURCE_FILE){ + errMsg("No audio file specified\n"); + } else { + errMsg("No audio data\n"); + } + return(-1); + } + + + if (!PlaySound((LPCSTR)audioSetup.beep,0,SND_MEMORY|SND_ASYNC)) + { + errMsg("Error playing WAVE.\n"); + if ( beep==audioSetup.beep || beep==0 || + !PlaySound((LPCSTR)beep,0,SND_MEMORY|SND_ASYNC)) + { + return(-1); + } + } + return 0; +} + +/****************************************************** + alBeep +******************************************************/ +void alBeep(Display *displayBB) +{ + int percent; + + percent = 100; + + if (audioSetup.port==AUDIO_INTERNAL_SPEAKER){ + XBell(displayBB,percent); + /*MessageBeep(-1);*/ + } else { + if (alAudioBeep()){ + XBell(displayBB,percent); + /*MessageBeep(-1);*/ + } + } +} + +/****************************************************** + audioSetupCreateDialog +******************************************************/ +static void audioSetupCreateDialog(Widget menuButton) +{ + Widget audioSetupDialogShell; + Widget form,form1; + Widget filename; + Widget button; + Widget toggleButton; + Widget frame, rowcol; + Widget label; + Pixel textBackground; + XmString string; + static ActionAreaItem audioSetup_items[] = { + { "Dismiss", audioSetupDismissCallback, NULL} }; + ALINK *area; + + textBackground = bg_pixel[3]; + + XtVaGetValues(menuButton, XmNuserData, &area, NULL); + + if (audioSetup.audioSetupDialog){ + if (XtIsManaged(audioSetup.audioSetupDialog)) return; + else XtManageChild(audioSetup.audioSetupDialog); + } + + audioSetupDialogShell = XtVaCreatePopupShell("ALH Audio Setup", + transientShellWidgetClass, area->toplevel, NULL, 0); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(audioSetupDialogShell, + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(audioSetupDialogShell), + "WM_DELETE_WINDOW", False); + XmAddWMProtocolCallback(audioSetupDialogShell,WM_DELETE_WINDOW, + (XtCallbackProc)audioSetupDismissCallback, (XtPointer)menuButton); + } + + form = XtVaCreateWidget("audioSetupDialog", + xmFormWidgetClass, audioSetupDialogShell, + NULL); + audioSetup.audioSetupDialog = form; + + string = XmStringCreateSimple("Audio Beep Output"); + label = XtVaCreateManagedWidget("audioOutputLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_FORM, + XmNtopWidget, form, + NULL); + XmStringFree(string); + + frame = XtVaCreateWidget("frame", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, label, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + rowcol = XtVaCreateWidget("rowcol", + xmRowColumnWidgetClass, frame, + XmNspacing, 0, + XmNmarginWidth, 10, + XmNmarginHeight, 10, + XmNradioBehavior, TRUE, + XmNbackground, textBackground, + NULL); + + toggleButton = XtVaCreateManagedWidget("Internal speaker", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + NULL); + XmToggleButtonSetState(toggleButton, + (Boolean)((audioSetup.port==AUDIO_INTERNAL_SPEAKER)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupOutputChangeCallback, (XtPointer)AUDIO_INTERNAL_SPEAKER); + + toggleButton = XtVaCreateManagedWidget("Default digital audio output", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + NULL); + XmToggleButtonSetState(toggleButton, + (Boolean)((audioSetup.port==AUDIO_DEFAULT_OUTPUT)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupOutputChangeCallback, (XtPointer)AUDIO_DEFAULT_OUTPUT); + + XtManageChild(rowcol); + XtManageChild(frame); + + string = XmStringCreateSimple("Audio Beep Source"); + label = XtVaCreateManagedWidget("audioBeepSourceLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, frame, + NULL); + XmStringFree(string); + + frame = XtVaCreateWidget("frame", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, label, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + audioSetup.beepSourceFrameWidget = frame; + if (audioSetup.port==AUDIO_INTERNAL_SPEAKER) XtSetSensitive(frame, FALSE); + else XtSetSensitive(frame, TRUE); + + rowcol = XtVaCreateWidget("rowcol", + xmRowColumnWidgetClass, frame, + XmNspacing, 0, + XmNmarginWidth, 10, + XmNmarginHeight, 10, + XmNradioBehavior, TRUE, + XmNbackground, textBackground, + NULL); + + toggleButton = XtVaCreateManagedWidget("alh internal beep", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + /*1XmNalignment,XmALIGNMENT_CENTER*/ + NULL); + XmToggleButtonSetState(toggleButton, + (Boolean)((audioSetup.beepSource==BEEP_AUDIO_SOURCE_INTERNAL)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupBeepSourceChangeCallback, + (XtPointer)BEEP_AUDIO_SOURCE_INTERNAL); + + if ( audioSetup.beep==0 ) { + audioSetup.beep = beep; + audioSetup.beepLength = beepLength; + } + + toggleButton = XtVaCreateManagedWidget("WAV (.wav) file", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + NULL); + XmToggleButtonSetState(toggleButton, + (Boolean)((audioSetup.beepSource==BEEP_AUDIO_SOURCE_FILE)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupBeepSourceChangeCallback, (XtPointer)BEEP_AUDIO_SOURCE_FILE); + + XtManageChild(rowcol); + XtManageChild(frame); + + string = XmStringCreateSimple("WAVE (.wav) filename"); + label = XtVaCreateManagedWidget("audioFilenamelabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, frame, + NULL); + XmStringFree(string); + + button = XtVaCreateManagedWidget("Browse", + xmPushButtonWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, frame, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, label, + XmNrightAttachment, XmATTACH_FORM, + XmNshadowThickness, 1, + NULL); + + filename = XtVaCreateManagedWidget("filename", + xmTextFieldWidgetClass, form, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, button, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtAddCallback(button, XmNactivateCallback, + audioSetupFilenameBrowseCallback, filename); + + XmTextFieldSetString(filename,audioSetup.beepFileName); + + XtAddCallback(filename, XmNactivateCallback, + audioSetupFilenameChangeCallback, NULL); + + string = XmStringCreateSimple("Test Beep"); + label = XtVaCreateManagedWidget("audioTestlabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, filename, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + button = XtVaCreateManagedWidget("Beep", + xmPushButtonWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, label, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNshadowThickness, 2, + NULL); + XtAddCallback(button, XmNactivateCallback, + audioSetupTestBeepCallback, NULL); + + /* Set the client data "Dismiss" button's callbacks. */ + audioSetup_items[0].data = (XtPointer)menuButton; + + form1 = createActionButtons(form, audioSetup_items, + XtNumber(audioSetup_items)); + if (form1) XtVaSetValues(form1, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, button, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtManageChild(form); + XtRealizeWidget(audioSetupDialogShell); +} + +/****************************************************** + audioSetupDismissCallback +******************************************************/ +static void audioSetupDismissCallback(Widget widget, XtPointer clientdata, +XtPointer cbs) +{ + Widget menuButton=(Widget)clientdata; + Widget dialog; + + dialog=audioSetup.audioSetupDialog; + XtUnmanageChild(dialog); + XUnmapWindow(XtDisplay(dialog), XtWindow(XtParent(dialog))); + if (menuButton) XtVaSetValues(menuButton, XmNset, FALSE, NULL); +} + +/****************************************************** + audioSetupTestBeepCallback +******************************************************/ +static void audioSetupTestBeepCallback( Widget widget, XtPointer clientdata, XtPointer cbs) +{ + alBeep(XtDisplay(widget)); +} + +/****************************************************** + audioSetupBeepSourceChangeCallback +******************************************************/ +static void audioSetupBeepSourceChangeCallback( Widget widget, + XtPointer clientdata, XtPointer cbs) +{ + XmToggleButtonCallbackStruct *state = + (XmToggleButtonCallbackStruct *) cbs; + + if (state->set) { + audioSetup.beepSource = (int)clientdata; + + switch (audioSetup.beepSource) { + case BEEP_AUDIO_SOURCE_INTERNAL: + audioSetup.beep = beep; + audioSetup.beepLength = beepLength; + break; + case BEEP_AUDIO_SOURCE_FILE: + audioSetup.beep = audioSetup.beepFileData; + audioSetup.beepLength = audioSetup.beepFileLength; + break; + } + } +} + +/****************************************************** + audioSetupOutputChangeCallback +******************************************************/ +static void audioSetupOutputChangeCallback( Widget widget, + XtPointer clientdata, XtPointer cbs) +{ + XmToggleButtonCallbackStruct *state = + (XmToggleButtonCallbackStruct *) cbs; + + if (state->set) { + audioSetup.port = (int)clientdata; + + if (audioSetup.port==AUDIO_INTERNAL_SPEAKER){ + XtSetSensitive(audioSetup.beepSourceFrameWidget, FALSE); + } else { + XtSetSensitive(audioSetup.beepSourceFrameWidget, TRUE); + } + } +} + +/****************************************************** + audioSetupFileSelectCallback +******************************************************/ +void audioSetupFileSelectCallback(Widget widget, XtPointer clientdata, +XtPointer *cbs) +{ + char *string; + + /* get the filename string */ + XmStringGetLtoR(((XmFileSelectionBoxCallbackStruct *)cbs)->value, + XmSTRING_DEFAULT_CHARSET, &string); + + if (strlen(string) && + !audioSetupNewFilename((Widget)clientdata,string)) + XtUnmanageChild(widget); + XtFree(string); +} + +/****************************************************** + audioSetupFilenameChangeCallback +******************************************************/ +static void audioSetupFilenameBrowseCallback( Widget widget, + XtPointer clientdata, XtPointer cbs) +{ + createFileDialog(widget, + (void *)audioSetupFileSelectCallback,(XtPointer)clientdata, + (void *)XtUnmanageChild,(XtPointer)0, + (XtPointer)0,"Au/u-law (.au) file",WAV_PATTERN,(char *)0); +} + +/****************************************************** + audioSetupFilenameChangeCallback +******************************************************/ +static void audioSetupFilenameChangeCallback( Widget widget, + XtPointer clientdata, XtPointer cbs) +{ + char * string; + + string = XmTextFieldGetString(widget); + audioSetupNewFilename(widget,string); + XtFree(string); +} + +/****************************************************** + audioSetupNewFilename +******************************************************/ +static int audioSetupNewFilename(Widget widget, char *string) +{ + char * filename; + char * plast; + int filenameSize; + unsigned long fileSize; + unsigned long beepLength; + FILE * fp; + unsigned char* beep; + + filename = string; + + /* remove leabeep white space */ + while (isspace(*filename)) { + filename++; + continue; + } + + /* remove trailing white space */ + plast=filename + strlen(filename)-1; + while (isspace(*plast)) { + *plast=0; + plast--; + } + + filenameSize = strlen(filename); + if (!filenameSize) return 0; + if (filename[filenameSize-1]=='/'||filename[filenameSize-1]=='\\') return 0; + + XmTextFieldSetString(widget,filename); + + if (audioSetup.beepFileName) free(audioSetup.beepFileName); + audioSetup.beepFileName=(char *)calloc(1,strlen(filename)+1); + strcpy(audioSetup.beepFileName,filename); + + audioSetup.beepFileLength = 0; + if (audioSetup.beepFileData) free(audioSetup.beepFileData); + audioSetup.beepFileData = 0; + + if (audioSetup.beepSource==BEEP_AUDIO_SOURCE_FILE){ + audioSetup.beep = audioSetup.beepFileData; + audioSetup.beepLength = audioSetup.beepFileLength; + } + + fp = fopen(filename,"rb"); + if(!fp) { + errMsg("Error: %s Could not open audio file %s.\n", + strerror(errno),filename); + return -1; + } + + /* Get size of audio file */ + fseek(fp,0L,SEEK_END); + fileSize=ftell(fp); + if(fileSize==-1) { + errMsg("Error determining size of audio file %s.\n",filename); + fclose( fp ); + return -1; + } + fseek(fp,0L,SEEK_SET); + + beep = calloc(fileSize,sizeof(char)); + if(!beep) { + errMsg("Error allocating memory for audio file %s.\n",filename); + fclose( fp ); + return -1; + } + + beepLength = fread(beep,sizeof(char),fileSize,fp); + if(feof(fp)) { + errMsg("Error reabeep audio file %s. End of file encountered.\n",filename); + fclose( fp ); + return -1; + } + if(beepLength != fileSize) { + errMsg("Error reabeep audio file %s.\n",filename); + fclose( fp ); + return -1; + } + fclose( fp ); + + audioSetup.beepFileLength = beepLength; + if (audioSetup.beepFileData) free(audioSetup.beepFileData); + audioSetup.beepFileData = beep; + + if (audioSetup.beepSource==BEEP_AUDIO_SOURCE_FILE){ + audioSetup.beep = audioSetup.beepFileData; + audioSetup.beepLength = audioSetup.beepFileLength; + } + return 0; +} diff --git a/os/WIN32/alAudio.h b/os/WIN32/alAudio.h new file mode 100644 index 0000000..8cc692a --- /dev/null +++ b/os/WIN32/alAudio.h @@ -0,0 +1,22 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alAudio.h */ + +#include "axArea.h" + +#define AUDIO_BEEP 1 + +extern void alhAudioSetupCallback( Widget widget, XtPointer calldata, XtPointer cbs); + diff --git a/os/WIN32/beep.h b/os/WIN32/beep.h new file mode 100644 index 0000000..0f97f5c --- /dev/null +++ b/os/WIN32/beep.h @@ -0,0 +1,983 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +int beepLength = 11598 ; +unsigned char beep[] = { +0x52, 0x49, 0x46, 0x46, 0x46, 0x2d, 0x0, 0x0, 0x57, 0x41, 0x56, 0x45, +0x66, 0x6d, 0x74, 0x20, 0x10, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x0, +0x22, 0x56, 0x0, 0x0, 0x22, 0x56, 0x0, 0x0, 0x1, 0x0, 0x8, 0x0, +0x64, 0x61, 0x74, 0x61, 0x22, 0x2d, 0x0, 0x0, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, +0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +0x7e, 0x7f, 0x94, 0xa4, 0x93, 0x64, 0x47, 0x5a, 0x70, 0x70, 0x70, 0x77, +0x86, 0x97, 0x93, 0x80, 0x79, 0x7c, 0x80, 0x92, 0x9e, 0x91, 0x83, 0x7a, +0x70, 0x7d, 0x91, 0x93, 0x90, 0x84, 0x67, 0x5c, 0x69, 0x75, 0x83, 0x89, +0x72, 0x5f, 0x63, 0x6d, 0x84, 0x9e, 0x98, 0x86, 0x7c, 0x73, 0x7f, 0x9f, +0xab, 0xa4, 0x96, 0x7a, 0x6e, 0x81, 0x92, 0x97, 0x96, 0x7c, 0x5f, 0x5b, +0x5d, 0x66, 0x7f, 0x85, 0x75, 0x6c, 0x66, 0x66, 0x80, 0x92, 0x8c, 0x87, +0x7d, 0x75, 0x88, 0xa0, 0xa7, 0xac, 0xa1, 0x85, 0x7c, 0x82, 0x87, 0x94, +0x96, 0x7e, 0x6a, 0x63, 0x5e, 0x6c, 0x7c, 0x74, 0x68, 0x61, 0x59, 0x65, +0x81, 0x8d, 0x91, 0x8f, 0x7c, 0x75, 0x88, 0x9a, 0xab, 0xb6, 0xa2, 0x89, +0x83, 0x82, 0x8b, 0x9c, 0x94, 0x7e, 0x6f, 0x60, 0x5e, 0x73, 0x7d, 0x77, +0x6e, 0x5c, 0x50, 0x60, 0x77, 0x86, 0x93, 0x8b, 0x76, 0x77, 0x85, 0x95, +0xad, 0xb2, 0xa1, 0x92, 0x88, 0x83, 0x93, 0x9f, 0x96, 0x87, 0x73, 0x5f, +0x63, 0x72, 0x76, 0x76, 0x6c, 0x55, 0x4f, 0x5e, 0x6e, 0x85, 0x93, 0x85, +0x77, 0x78, 0x7f, 0x96, 0xae, 0xad, 0xa3, 0x98, 0x85, 0x83, 0x93, 0x9c, +0x9a, 0x8d, 0x72, 0x60, 0x66, 0x6e, 0x75, 0x79, 0x69, 0x56, 0x54, 0x5b, +0x6c, 0x85, 0x8d, 0x84, 0x7d, 0x77, 0x7d, 0x97, 0xab, 0xad, 0xa6, 0x94, +0x84, 0x89, 0x95, 0x9a, 0x99, 0x88, 0x6d, 0x60, 0x62, 0x69, 0x77, 0x79, +0x68, 0x59, 0x53, 0x57, 0x6d, 0x85, 0x8a, 0x85, 0x7e, 0x77, 0x82, 0x9b, +0xa9, 0xaf, 0xa9, 0x93, 0x85, 0x89, 0x92, 0x9e, 0x9d, 0x85, 0x6b, 0x5f, +0x5d, 0x67, 0x74, 0x71, 0x63, 0x58, 0x50, 0x57, 0x70, 0x84, 0x8c, 0x8c, +0x80, 0x7a, 0x88, 0x9d, 0xad, 0xb6, 0xab, 0x96, 0x8c, 0x8b, 0x92, 0x9e, +0x9b, 0x85, 0x70, 0x5e, 0x56, 0x62, 0x6f, 0x6d, 0x65, 0x56, 0x4b, 0x56, +0x6f, 0x81, 0x8d, 0x8d, 0x7f, 0x7e, 0x8b, 0x9c, 0xb2, 0xbd, 0xae, 0x9b, +0x8e, 0x89, 0x94, 0xa0, 0x99, 0x85, 0x6f, 0x5a, 0x56, 0x63, 0x6b, 0x6b, +0x64, 0x51, 0x48, 0x54, 0x67, 0x7d, 0x8f, 0x8b, 0x7e, 0x7e, 0x88, 0x9d, +0xb6, 0xbb, 0xaf, 0xa0, 0x91, 0x8d, 0x99, 0xa2, 0x9c, 0x8c, 0x71, 0x59, +0x57, 0x60, 0x69, 0x6c, 0x61, 0x4c, 0x46, 0x4e, 0x60, 0x7a, 0x8a, 0x86, +0x7f, 0x7c, 0x83, 0x9d, 0xb6, 0xbb, 0xb4, 0xa4, 0x91, 0x91, 0x9d, 0xa3, +0xa2, 0x92, 0x74, 0x5f, 0x5c, 0x5f, 0x69, 0x6d, 0x5e, 0x4b, 0x44, 0x48, +0x5c, 0x78, 0x84, 0x82, 0x7d, 0x78, 0x81, 0x9b, 0xaf, 0xb8, 0xb6, 0xa5, +0x94, 0x95, 0x9d, 0xa5, 0xa8, 0x96, 0x79, 0x66, 0x5e, 0x61, 0x6d, 0x6e, +0x5e, 0x4f, 0x44, 0x45, 0x5b, 0x72, 0x7e, 0x80, 0x79, 0x72, 0x7e, 0x96, +0xaa, 0xb7, 0xb4, 0xa2, 0x96, 0x97, 0x9d, 0xa9, 0xac, 0x98, 0x80, 0x6c, +0x5f, 0x65, 0x71, 0x6f, 0x63, 0x53, 0x44, 0x46, 0x5b, 0x6e, 0x7c, 0x7f, +0x74, 0x70, 0x7c, 0x8f, 0xa6, 0xb6, 0xb1, 0xa1, 0x97, 0x93, 0x9c, 0xab, +0xaa, 0x9a, 0x85, 0x6e, 0x62, 0x6a, 0x72, 0x71, 0x68, 0x54, 0x44, 0x48, +0x59, 0x6d, 0x7f, 0x7e, 0x72, 0x6f, 0x77, 0x8a, 0xa6, 0xb4, 0xaf, 0xa4, +0x97, 0x91, 0x9c, 0xa9, 0xa9, 0x9e, 0x86, 0x6c, 0x65, 0x6b, 0x71, 0x74, +0x6b, 0x55, 0x47, 0x4a, 0x57, 0x6e, 0x80, 0x7d, 0x75, 0x71, 0x75, 0x8a, +0xa5, 0xb2, 0xb0, 0xa5, 0x96, 0x92, 0x9c, 0xa4, 0xa5, 0x9d, 0x84, 0x6c, +0x65, 0x69, 0x72, 0x78, 0x6c, 0x55, 0x49, 0x49, 0x58, 0x71, 0x7f, 0x7d, +0x76, 0x6f, 0x74, 0x8b, 0xa3, 0xb0, 0xb1, 0xa3, 0x91, 0x90, 0x9a, 0xa5, +0xab, 0x9f, 0x84, 0x6f, 0x66, 0x68, 0x74, 0x78, 0x6a, 0x58, 0x4a, 0x47, +0x58, 0x71, 0x7e, 0x80, 0x77, 0x6d, 0x74, 0x8b, 0xa2, 0xb1, 0xb2, 0xa2, +0x94, 0x92, 0x99, 0xa5, 0xad, 0xa0, 0x88, 0x72, 0x65, 0x68, 0x75, 0x77, +0x6b, 0x5a, 0x48, 0x46, 0x57, 0x6c, 0x7c, 0x81, 0x78, 0x6e, 0x74, 0x87, +0x9e, 0xb2, 0xb2, 0xa3, 0x98, 0x93, 0x99, 0xa8, 0xac, 0x9f, 0x8b, 0x74, +0x65, 0x6a, 0x74, 0x75, 0x6e, 0x5c, 0x48, 0x47, 0x56, 0x69, 0x7c, 0x80, +0x74, 0x6e, 0x74, 0x84, 0x9e, 0xb0, 0xb0, 0xa5, 0x99, 0x92, 0x9a, 0xa9, +0xac, 0xa2, 0x8d, 0x74, 0x68, 0x6d, 0x73, 0x76, 0x6f, 0x5b, 0x49, 0x48, +0x52, 0x67, 0x7b, 0x7d, 0x74, 0x6d, 0x6f, 0x81, 0x9c, 0xae, 0xaf, 0xa6, +0x99, 0x93, 0x9c, 0xa8, 0xab, 0xa5, 0x8f, 0x77, 0x6c, 0x6d, 0x74, 0x79, +0x71, 0x5b, 0x4b, 0x48, 0x51, 0x67, 0x78, 0x7a, 0x74, 0x6e, 0x6e, 0x81, +0x9a, 0xab, 0xaf, 0xa7, 0x98, 0x94, 0x9d, 0xa7, 0xac, 0xa5, 0x8f, 0x7a, +0x6e, 0x6c, 0x74, 0x7a, 0x70, 0x5e, 0x4e, 0x47, 0x51, 0x67, 0x77, 0x7a, +0x75, 0x6c, 0x6e, 0x81, 0x98, 0xa8, 0xae, 0xa4, 0x97, 0x94, 0x9a, 0xa5, +0xae, 0xa6, 0x90, 0x7c, 0x6e, 0x6e, 0x77, 0x7b, 0x71, 0x61, 0x4f, 0x48, +0x53, 0x67, 0x76, 0x7d, 0x77, 0x6b, 0x6d, 0x7d, 0x94, 0xa8, 0xac, 0xa2, +0x97, 0x93, 0x98, 0xa5, 0xac, 0xa4, 0x92, 0x7d, 0x6e, 0x6e, 0x78, 0x7b, +0x74, 0x63, 0x50, 0x4a, 0x54, 0x66, 0x76, 0x7c, 0x74, 0x6b, 0x6e, 0x7c, +0x92, 0xa6, 0xaa, 0xa2, 0x97, 0x91, 0x97, 0xa4, 0xab, 0xa4, 0x92, 0x7c, +0x6f, 0x70, 0x77, 0x7b, 0x75, 0x65, 0x52, 0x4c, 0x54, 0x65, 0x77, 0x7c, +0x74, 0x6d, 0x6e, 0x7b, 0x92, 0xa4, 0xa8, 0xa1, 0x96, 0x8f, 0x95, 0xa1, +0xa8, 0xa3, 0x92, 0x7c, 0x6f, 0x6f, 0x76, 0x7c, 0x76, 0x65, 0x53, 0x4d, +0x54, 0x65, 0x76, 0x7b, 0x76, 0x6e, 0x6d, 0x7a, 0x91, 0xa3, 0xa8, 0xa1, +0x95, 0x8f, 0x96, 0xa1, 0xa7, 0xa3, 0x91, 0x7d, 0x70, 0x6f, 0x76, 0x7c, +0x77, 0x66, 0x55, 0x4d, 0x54, 0x66, 0x76, 0x7b, 0x76, 0x6e, 0x6e, 0x7b, +0x90, 0xa1, 0xa8, 0xa1, 0x95, 0x8f, 0x95, 0xa0, 0xa8, 0xa4, 0x92, 0x7e, +0x71, 0x6f, 0x76, 0x7c, 0x76, 0x67, 0x57, 0x4e, 0x53, 0x64, 0x74, 0x7b, +0x77, 0x6e, 0x6d, 0x7a, 0x8f, 0xa1, 0xa7, 0xa1, 0x96, 0x91, 0x95, 0x9f, +0xa8, 0xa4, 0x94, 0x80, 0x71, 0x6f, 0x77, 0x7c, 0x77, 0x68, 0x57, 0x4e, +0x54, 0x64, 0x73, 0x7a, 0x76, 0x6e, 0x6d, 0x79, 0x8d, 0xa0, 0xa7, 0xa1, +0x96, 0x90, 0x94, 0xa0, 0xa8, 0xa4, 0x95, 0x81, 0x73, 0x71, 0x77, 0x7c, +0x79, 0x6a, 0x58, 0x4f, 0x54, 0x63, 0x73, 0x7a, 0x74, 0x6d, 0x6d, 0x77, +0x8b, 0x9e, 0xa5, 0xa0, 0x96, 0x8f, 0x93, 0x9f, 0xa8, 0xa5, 0x97, 0x82, +0x74, 0x72, 0x78, 0x7d, 0x7a, 0x6b, 0x5a, 0x50, 0x54, 0x62, 0x72, 0x79, +0x75, 0x6d, 0x6b, 0x75, 0x89, 0x9c, 0xa3, 0x9f, 0x95, 0x8f, 0x93, 0x9e, +0xa6, 0xa5, 0x97, 0x84, 0x75, 0x72, 0x78, 0x7e, 0x7b, 0x6d, 0x5b, 0x51, +0x54, 0x63, 0x72, 0x77, 0x73, 0x6c, 0x6a, 0x73, 0x86, 0x98, 0xa1, 0x9e, +0x94, 0x8d, 0x91, 0x9b, 0xa4, 0xa5, 0x98, 0x86, 0x78, 0x74, 0x78, 0x7e, +0x7d, 0x71, 0x60, 0x55, 0x55, 0x60, 0x6f, 0x77, 0x76, 0x6e, 0x6a, 0x72, +0x83, 0x95, 0x9f, 0x9e, 0x95, 0x8e, 0x90, 0x99, 0xa3, 0xa5, 0x9b, 0x8a, +0x7a, 0x74, 0x78, 0x7f, 0x7e, 0x73, 0x63, 0x57, 0x55, 0x5f, 0x6d, 0x76, +0x77, 0x6f, 0x6a, 0x70, 0x7f, 0x92, 0x9e, 0x9e, 0x96, 0x8f, 0x8f, 0x97, +0xa2, 0xa5, 0x9d, 0x8d, 0x7d, 0x76, 0x78, 0x7e, 0x7f, 0x77, 0x67, 0x59, +0x56, 0x5f, 0x6c, 0x76, 0x77, 0x70, 0x6b, 0x6f, 0x7d, 0x90, 0x9c, 0x9e, +0x97, 0x8f, 0x8e, 0x96, 0xa1, 0xa5, 0x9e, 0x8e, 0x7e, 0x77, 0x79, 0x7e, +0x7f, 0x77, 0x68, 0x5a, 0x57, 0x5e, 0x6c, 0x77, 0x77, 0x71, 0x6b, 0x6f, +0x7d, 0x8f, 0x9b, 0x9d, 0x97, 0x90, 0x8f, 0x96, 0xa0, 0xa5, 0x9f, 0x8f, +0x7f, 0x77, 0x79, 0x7f, 0x80, 0x78, 0x69, 0x5c, 0x58, 0x5e, 0x6c, 0x76, +0x77, 0x72, 0x6c, 0x6e, 0x7c, 0x8e, 0x9b, 0x9d, 0x97, 0x8f, 0x8f, 0x96, +0xa0, 0xa4, 0x9f, 0x90, 0x81, 0x79, 0x79, 0x7e, 0x80, 0x79, 0x6a, 0x5c, +0x57, 0x5e, 0x6b, 0x75, 0x77, 0x71, 0x6c, 0x6f, 0x7b, 0x8c, 0x99, 0x9d, +0x98, 0x90, 0x8f, 0x95, 0x9f, 0xa4, 0x9f, 0x91, 0x82, 0x79, 0x7a, 0x7f, +0x80, 0x79, 0x6b, 0x5e, 0x58, 0x5e, 0x6a, 0x75, 0x77, 0x72, 0x6c, 0x6e, +0x7a, 0x8b, 0x99, 0x9c, 0x97, 0x90, 0x8f, 0x95, 0x9f, 0xa4, 0x9f, 0x92, +0x83, 0x79, 0x79, 0x7f, 0x81, 0x7a, 0x6c, 0x5e, 0x58, 0x5e, 0x6a, 0x74, +0x76, 0x71, 0x6c, 0x6d, 0x79, 0x8a, 0x97, 0x9c, 0x97, 0x90, 0x8e, 0x95, +0x9f, 0xa4, 0x9f, 0x92, 0x84, 0x7b, 0x7a, 0x7f, 0x81, 0x7b, 0x6d, 0x5f, +0x59, 0x5e, 0x69, 0x74, 0x76, 0x71, 0x6c, 0x6d, 0x78, 0x89, 0x96, 0x9b, +0x97, 0x90, 0x8e, 0x94, 0x9d, 0xa3, 0xa0, 0x93, 0x84, 0x7b, 0x7a, 0x7f, +0x81, 0x7b, 0x6d, 0x60, 0x59, 0x5d, 0x68, 0x72, 0x76, 0x71, 0x6b, 0x6c, +0x77, 0x87, 0x95, 0x9a, 0x96, 0x8f, 0x8e, 0x93, 0x9d, 0xa2, 0x9f, 0x93, +0x85, 0x7b, 0x7a, 0x7f, 0x81, 0x7c, 0x6f, 0x61, 0x5a, 0x5d, 0x68, 0x72, +0x75, 0x71, 0x6c, 0x6c, 0x76, 0x86, 0x93, 0x99, 0x96, 0x8f, 0x8d, 0x92, +0x9c, 0xa2, 0x9f, 0x93, 0x85, 0x7c, 0x7a, 0x7f, 0x81, 0x7c, 0x70, 0x62, +0x5a, 0x5d, 0x67, 0x72, 0x75, 0x71, 0x6b, 0x6c, 0x75, 0x85, 0x93, 0x98, +0x95, 0x8f, 0x8d, 0x92, 0x9b, 0xa2, 0x9f, 0x94, 0x86, 0x7c, 0x7b, 0x7f, +0x82, 0x7d, 0x70, 0x63, 0x5b, 0x5e, 0x67, 0x71, 0x75, 0x72, 0x6c, 0x6c, +0x74, 0x84, 0x92, 0x98, 0x95, 0x8f, 0x8d, 0x92, 0x9b, 0xa1, 0x9f, 0x95, +0x87, 0x7d, 0x7b, 0x7f, 0x82, 0x7e, 0x72, 0x64, 0x5c, 0x5e, 0x67, 0x71, +0x75, 0x72, 0x6c, 0x6c, 0x74, 0x82, 0x90, 0x97, 0x95, 0x8f, 0x8c, 0x90, +0x99, 0xa0, 0xa0, 0x96, 0x88, 0x7e, 0x7b, 0x7f, 0x82, 0x7e, 0x73, 0x66, +0x5d, 0x5d, 0x66, 0x70, 0x75, 0x73, 0x6d, 0x6c, 0x72, 0x80, 0x8f, 0x97, +0x95, 0x90, 0x8c, 0x90, 0x98, 0x9f, 0xa0, 0x97, 0x8a, 0x7f, 0x7b, 0x7d, +0x81, 0x7f, 0x75, 0x67, 0x5e, 0x5d, 0x65, 0x6f, 0x75, 0x73, 0x6e, 0x6c, +0x71, 0x7f, 0x8d, 0x96, 0x96, 0x91, 0x8c, 0x8e, 0x96, 0x9e, 0xa0, 0x99, +0x8c, 0x80, 0x7b, 0x7d, 0x81, 0x80, 0x77, 0x6b, 0x60, 0x5e, 0x64, 0x6e, +0x75, 0x75, 0x70, 0x6c, 0x70, 0x7c, 0x8a, 0x94, 0x96, 0x91, 0x8c, 0x8d, +0x94, 0x9c, 0x9f, 0x9a, 0x8f, 0x82, 0x7c, 0x7c, 0x80, 0x81, 0x7a, 0x6e, +0x62, 0x5e, 0x62, 0x6c, 0x74, 0x75, 0x71, 0x6d, 0x6f, 0x79, 0x87, 0x92, +0x96, 0x92, 0x8d, 0x8c, 0x92, 0x9a, 0x9f, 0x9c, 0x91, 0x85, 0x7d, 0x7c, +0x80, 0x81, 0x7c, 0x71, 0x65, 0x5f, 0x61, 0x6a, 0x72, 0x75, 0x72, 0x6e, +0x6e, 0x76, 0x84, 0x90, 0x95, 0x93, 0x8e, 0x8c, 0x91, 0x98, 0x9e, 0x9c, +0x93, 0x87, 0x7e, 0x7c, 0x7f, 0x81, 0x7d, 0x73, 0x67, 0x5f, 0x60, 0x69, +0x72, 0x75, 0x73, 0x6e, 0x6e, 0x75, 0x82, 0x8e, 0x95, 0x94, 0x8f, 0x8c, +0x8f, 0x97, 0x9d, 0x9d, 0x95, 0x88, 0x7f, 0x7c, 0x7e, 0x81, 0x7e, 0x74, +0x68, 0x60, 0x60, 0x68, 0x71, 0x75, 0x74, 0x6f, 0x6d, 0x73, 0x80, 0x8d, +0x94, 0x94, 0x8f, 0x8c, 0x8f, 0x96, 0x9d, 0x9d, 0x95, 0x89, 0x80, 0x7c, +0x7e, 0x81, 0x7f, 0x76, 0x6a, 0x61, 0x60, 0x66, 0x70, 0x75, 0x74, 0x6f, +0x6d, 0x72, 0x7e, 0x8b, 0x93, 0x94, 0x90, 0x8c, 0x8d, 0x94, 0x9c, 0x9d, +0x97, 0x8b, 0x81, 0x7c, 0x7e, 0x81, 0x80, 0x78, 0x6c, 0x62, 0x60, 0x66, +0x6f, 0x75, 0x75, 0x71, 0x6e, 0x71, 0x7c, 0x8a, 0x93, 0x94, 0x90, 0x8c, +0x8d, 0x93, 0x9b, 0x9d, 0x98, 0x8d, 0x82, 0x7c, 0x7d, 0x80, 0x80, 0x79, +0x6d, 0x63, 0x60, 0x65, 0x6e, 0x75, 0x75, 0x71, 0x6e, 0x71, 0x7b, 0x88, +0x92, 0x94, 0x91, 0x8c, 0x8c, 0x92, 0x9a, 0x9d, 0x99, 0x8e, 0x83, 0x7c, +0x7d, 0x80, 0x81, 0x7b, 0x6f, 0x65, 0x60, 0x64, 0x6d, 0x74, 0x76, 0x72, +0x6e, 0x70, 0x79, 0x86, 0x91, 0x94, 0x91, 0x8c, 0x8c, 0x91, 0x99, 0x9d, +0x99, 0x8f, 0x84, 0x7d, 0x7c, 0x80, 0x81, 0x7c, 0x71, 0x66, 0x60, 0x64, +0x6c, 0x74, 0x76, 0x72, 0x6e, 0x6f, 0x78, 0x85, 0x90, 0x94, 0x91, 0x8d, +0x8b, 0x90, 0x98, 0x9c, 0x9a, 0x91, 0x85, 0x7d, 0x7c, 0x80, 0x81, 0x7d, +0x72, 0x67, 0x61, 0x63, 0x6b, 0x73, 0x76, 0x73, 0x6f, 0x6f, 0x77, 0x83, +0x8f, 0x94, 0x92, 0x8d, 0x8b, 0x8f, 0x97, 0x9c, 0x9a, 0x92, 0x86, 0x7e, +0x7c, 0x7f, 0x81, 0x7e, 0x74, 0x68, 0x62, 0x63, 0x6b, 0x73, 0x76, 0x74, +0x6f, 0x6f, 0x76, 0x82, 0x8d, 0x93, 0x92, 0x8d, 0x8b, 0x8e, 0x95, 0x9b, +0x9b, 0x93, 0x87, 0x7f, 0x7c, 0x7f, 0x81, 0x7f, 0x75, 0x6a, 0x62, 0x62, +0x6a, 0x72, 0x77, 0x75, 0x71, 0x6f, 0x75, 0x80, 0x8c, 0x93, 0x92, 0x8d, +0x8a, 0x8d, 0x94, 0x9a, 0x9b, 0x94, 0x89, 0x7f, 0x7c, 0x7e, 0x81, 0x7f, +0x77, 0x6b, 0x63, 0x63, 0x69, 0x72, 0x77, 0x75, 0x71, 0x6f, 0x74, 0x7f, +0x8b, 0x92, 0x92, 0x8e, 0x8a, 0x8c, 0x93, 0x9a, 0x9b, 0x94, 0x89, 0x80, +0x7c, 0x7e, 0x81, 0x80, 0x78, 0x6d, 0x64, 0x63, 0x69, 0x71, 0x77, 0x76, +0x72, 0x6f, 0x73, 0x7d, 0x8a, 0x92, 0x92, 0x8e, 0x8b, 0x8c, 0x92, 0x99, +0x9a, 0x95, 0x8b, 0x81, 0x7c, 0x7d, 0x81, 0x80, 0x7a, 0x6e, 0x65, 0x63, +0x68, 0x70, 0x77, 0x77, 0x72, 0x70, 0x73, 0x7c, 0x88, 0x91, 0x92, 0x8f, +0x8b, 0x8b, 0x91, 0x98, 0x9a, 0x96, 0x8c, 0x81, 0x7c, 0x7d, 0x80, 0x81, +0x7b, 0x70, 0x66, 0x63, 0x67, 0x70, 0x76, 0x77, 0x73, 0x70, 0x72, 0x7b, +0x87, 0x90, 0x92, 0x8f, 0x8b, 0x8a, 0x8f, 0x96, 0x99, 0x96, 0x8d, 0x83, +0x7d, 0x7c, 0x7f, 0x81, 0x7c, 0x73, 0x69, 0x64, 0x67, 0x6e, 0x75, 0x77, +0x75, 0x71, 0x72, 0x79, 0x84, 0x8d, 0x92, 0x90, 0x8b, 0x8a, 0x8d, 0x94, +0x99, 0x97, 0x8f, 0x85, 0x7e, 0x7c, 0x7f, 0x81, 0x7e, 0x75, 0x6b, 0x65, +0x66, 0x6d, 0x74, 0x78, 0x76, 0x72, 0x71, 0x77, 0x81, 0x8c, 0x91, 0x90, +0x8c, 0x8a, 0x8c, 0x93, 0x98, 0x97, 0x91, 0x87, 0x7f, 0x7c, 0x7e, 0x80, +0x7f, 0x78, 0x6d, 0x66, 0x66, 0x6c, 0x73, 0x77, 0x76, 0x73, 0x71, 0x76, +0x7f, 0x8a, 0x90, 0x90, 0x8d, 0x8a, 0x8b, 0x91, 0x97, 0x98, 0x92, 0x88, +0x80, 0x7c, 0x7e, 0x80, 0x7f, 0x79, 0x6f, 0x67, 0x66, 0x6b, 0x73, 0x78, +0x77, 0x74, 0x71, 0x75, 0x7e, 0x89, 0x90, 0x90, 0x8d, 0x8a, 0x8b, 0x90, +0x96, 0x97, 0x93, 0x89, 0x81, 0x7c, 0x7d, 0x80, 0x80, 0x7a, 0x70, 0x68, +0x66, 0x6a, 0x72, 0x77, 0x77, 0x74, 0x72, 0x74, 0x7d, 0x88, 0x8f, 0x91, +0x8d, 0x8a, 0x8a, 0x8f, 0x95, 0x97, 0x93, 0x8a, 0x81, 0x7d, 0x7d, 0x80, +0x80, 0x7a, 0x71, 0x69, 0x66, 0x6a, 0x71, 0x77, 0x78, 0x75, 0x72, 0x74, +0x7c, 0x87, 0x8f, 0x91, 0x8e, 0x8a, 0x8a, 0x8f, 0x94, 0x97, 0x94, 0x8b, +0x82, 0x7d, 0x7d, 0x7f, 0x80, 0x7c, 0x73, 0x6a, 0x66, 0x6a, 0x71, 0x77, +0x78, 0x75, 0x72, 0x74, 0x7b, 0x85, 0x8e, 0x91, 0x8e, 0x8b, 0x8a, 0x8d, +0x94, 0x97, 0x95, 0x8d, 0x83, 0x7d, 0x7d, 0x7f, 0x80, 0x7c, 0x74, 0x6b, +0x66, 0x68, 0x70, 0x77, 0x79, 0x76, 0x73, 0x73, 0x7a, 0x84, 0x8d, 0x90, +0x8f, 0x8b, 0x8a, 0x8d, 0x93, 0x96, 0x95, 0x8e, 0x84, 0x7e, 0x7c, 0x7e, +0x80, 0x7d, 0x75, 0x6c, 0x67, 0x69, 0x6f, 0x75, 0x78, 0x76, 0x73, 0x73, +0x79, 0x83, 0x8b, 0x90, 0x8f, 0x8b, 0x8a, 0x8c, 0x92, 0x96, 0x95, 0x8e, +0x85, 0x7f, 0x7c, 0x7e, 0x80, 0x7d, 0x76, 0x6e, 0x68, 0x69, 0x6e, 0x75, +0x78, 0x77, 0x74, 0x73, 0x78, 0x81, 0x8b, 0x90, 0x8f, 0x8c, 0x8a, 0x8c, +0x91, 0x95, 0x95, 0x8f, 0x86, 0x7f, 0x7c, 0x7e, 0x80, 0x7e, 0x77, 0x6e, +0x68, 0x68, 0x6e, 0x74, 0x78, 0x77, 0x74, 0x73, 0x77, 0x80, 0x8a, 0x8f, +0x8f, 0x8c, 0x8a, 0x8b, 0x90, 0x95, 0x95, 0x90, 0x87, 0x80, 0x7d, 0x7e, +0x80, 0x7e, 0x78, 0x70, 0x69, 0x68, 0x6d, 0x73, 0x78, 0x78, 0x75, 0x73, +0x77, 0x7f, 0x89, 0x8f, 0x8f, 0x8c, 0x89, 0x8a, 0x8f, 0x94, 0x95, 0x91, +0x88, 0x80, 0x7d, 0x7d, 0x80, 0x7f, 0x7a, 0x71, 0x6a, 0x68, 0x6c, 0x73, +0x78, 0x78, 0x75, 0x73, 0x76, 0x7e, 0x87, 0x8e, 0x8f, 0x8d, 0x8a, 0x8a, +0x8e, 0x93, 0x95, 0x92, 0x89, 0x81, 0x7d, 0x7d, 0x80, 0x80, 0x7b, 0x72, +0x6b, 0x68, 0x6c, 0x72, 0x78, 0x79, 0x76, 0x73, 0x75, 0x7c, 0x86, 0x8e, +0x8f, 0x8d, 0x8a, 0x8a, 0x8d, 0x92, 0x94, 0x92, 0x8a, 0x82, 0x7e, 0x7d, +0x7f, 0x80, 0x7c, 0x74, 0x6c, 0x69, 0x6c, 0x72, 0x77, 0x78, 0x76, 0x74, +0x75, 0x7c, 0x84, 0x8c, 0x8f, 0x8d, 0x8a, 0x89, 0x8c, 0x92, 0x95, 0x92, +0x8b, 0x83, 0x7e, 0x7d, 0x80, 0x80, 0x7c, 0x75, 0x6d, 0x6a, 0x6c, 0x71, +0x77, 0x79, 0x77, 0x74, 0x75, 0x7b, 0x84, 0x8b, 0x8e, 0x8d, 0x8a, 0x89, +0x8c, 0x91, 0x94, 0x92, 0x8c, 0x84, 0x7e, 0x7d, 0x7f, 0x80, 0x7e, 0x77, +0x6f, 0x6b, 0x6c, 0x71, 0x77, 0x79, 0x77, 0x75, 0x75, 0x79, 0x81, 0x89, +0x8d, 0x8d, 0x8a, 0x88, 0x8a, 0x8f, 0x92, 0x92, 0x8d, 0x86, 0x80, 0x7e, +0x7f, 0x80, 0x7f, 0x79, 0x71, 0x6c, 0x6c, 0x70, 0x76, 0x79, 0x78, 0x76, +0x75, 0x78, 0x7f, 0x87, 0x8c, 0x8d, 0x8a, 0x88, 0x8a, 0x8d, 0x91, 0x92, +0x8e, 0x87, 0x81, 0x7e, 0x7e, 0x80, 0x7f, 0x7a, 0x73, 0x6d, 0x6c, 0x6f, +0x74, 0x78, 0x79, 0x76, 0x75, 0x77, 0x7e, 0x85, 0x8b, 0x8d, 0x8b, 0x88, +0x89, 0x8c, 0x90, 0x92, 0x8f, 0x89, 0x82, 0x7e, 0x7e, 0x80, 0x80, 0x7b, +0x75, 0x6e, 0x6c, 0x6f, 0x74, 0x78, 0x79, 0x77, 0x75, 0x77, 0x7c, 0x85, +0x8b, 0x8d, 0x8b, 0x88, 0x88, 0x8c, 0x90, 0x92, 0x90, 0x8a, 0x83, 0x7e, +0x7e, 0x7f, 0x80, 0x7c, 0x76, 0x6f, 0x6c, 0x6e, 0x73, 0x78, 0x79, 0x77, +0x75, 0x76, 0x7b, 0x83, 0x8a, 0x8d, 0x8b, 0x89, 0x88, 0x8b, 0x8f, 0x91, +0x90, 0x8a, 0x83, 0x7f, 0x7e, 0x80, 0x80, 0x7d, 0x77, 0x70, 0x6d, 0x6e, +0x73, 0x78, 0x79, 0x78, 0x75, 0x76, 0x7b, 0x83, 0x89, 0x8c, 0x8b, 0x88, +0x87, 0x8a, 0x8e, 0x91, 0x90, 0x8b, 0x84, 0x7f, 0x7e, 0x7f, 0x81, 0x7e, +0x78, 0x71, 0x6d, 0x6e, 0x73, 0x78, 0x7a, 0x78, 0x76, 0x75, 0x7a, 0x81, +0x88, 0x8c, 0x8b, 0x88, 0x87, 0x89, 0x8d, 0x91, 0x90, 0x8b, 0x85, 0x7f, +0x7e, 0x7f, 0x81, 0x7f, 0x79, 0x72, 0x6e, 0x6e, 0x72, 0x77, 0x7a, 0x79, +0x76, 0x76, 0x79, 0x80, 0x87, 0x8b, 0x8b, 0x88, 0x87, 0x89, 0x8d, 0x90, +0x90, 0x8c, 0x85, 0x80, 0x7e, 0x7f, 0x81, 0x7f, 0x7a, 0x73, 0x6e, 0x6e, +0x72, 0x77, 0x7a, 0x79, 0x76, 0x76, 0x79, 0x7f, 0x87, 0x8b, 0x8b, 0x89, +0x86, 0x88, 0x8c, 0x90, 0x90, 0x8c, 0x86, 0x80, 0x7e, 0x7f, 0x81, 0x80, +0x7b, 0x74, 0x6f, 0x6e, 0x72, 0x77, 0x7a, 0x7a, 0x77, 0x76, 0x78, 0x7f, +0x87, 0x8b, 0x8b, 0x88, 0x86, 0x87, 0x8b, 0x8f, 0x90, 0x8d, 0x86, 0x81, +0x7e, 0x7e, 0x80, 0x80, 0x7c, 0x75, 0x70, 0x6e, 0x71, 0x77, 0x7a, 0x7a, +0x78, 0x76, 0x78, 0x7e, 0x85, 0x8a, 0x8b, 0x89, 0x87, 0x87, 0x8a, 0x8e, +0x90, 0x8d, 0x87, 0x81, 0x7e, 0x7e, 0x80, 0x80, 0x7c, 0x76, 0x71, 0x6f, +0x71, 0x76, 0x7a, 0x7b, 0x78, 0x76, 0x78, 0x7d, 0x84, 0x8a, 0x8b, 0x89, +0x87, 0x87, 0x8a, 0x8e, 0x8f, 0x8d, 0x87, 0x81, 0x7e, 0x7e, 0x80, 0x80, +0x7d, 0x77, 0x71, 0x6f, 0x71, 0x76, 0x7a, 0x7b, 0x79, 0x77, 0x78, 0x7c, +0x83, 0x89, 0x8b, 0x89, 0x87, 0x86, 0x89, 0x8d, 0x8f, 0x8d, 0x88, 0x82, +0x7e, 0x7e, 0x80, 0x80, 0x7e, 0x78, 0x72, 0x6f, 0x71, 0x75, 0x7a, 0x7b, +0x79, 0x77, 0x77, 0x7c, 0x83, 0x89, 0x8b, 0x8a, 0x87, 0x86, 0x88, 0x8c, +0x8f, 0x8e, 0x89, 0x83, 0x7f, 0x7e, 0x80, 0x81, 0x7e, 0x79, 0x73, 0x70, +0x71, 0x75, 0x7a, 0x7b, 0x7a, 0x77, 0x77, 0x7b, 0x82, 0x88, 0x8b, 0x8a, +0x87, 0x86, 0x88, 0x8c, 0x8f, 0x8e, 0x89, 0x83, 0x7f, 0x7e, 0x7f, 0x81, +0x7f, 0x7a, 0x74, 0x70, 0x70, 0x75, 0x79, 0x7b, 0x7a, 0x77, 0x77, 0x7a, +0x81, 0x87, 0x8b, 0x8a, 0x87, 0x85, 0x87, 0x8b, 0x8f, 0x8e, 0x8a, 0x84, +0x7f, 0x7d, 0x7f, 0x80, 0x7f, 0x7a, 0x74, 0x70, 0x70, 0x74, 0x79, 0x7b, +0x7b, 0x78, 0x77, 0x7a, 0x80, 0x86, 0x8a, 0x8a, 0x88, 0x86, 0x86, 0x89, +0x8d, 0x8e, 0x8a, 0x85, 0x80, 0x7e, 0x7f, 0x80, 0x80, 0x7c, 0x76, 0x71, +0x71, 0x74, 0x78, 0x7b, 0x7b, 0x79, 0x77, 0x79, 0x7e, 0x85, 0x89, 0x8a, +0x88, 0x86, 0x86, 0x89, 0x8d, 0x8e, 0x8b, 0x86, 0x81, 0x7e, 0x7f, 0x80, +0x80, 0x7d, 0x78, 0x73, 0x71, 0x73, 0x77, 0x7b, 0x7b, 0x79, 0x78, 0x79, +0x7d, 0x83, 0x88, 0x89, 0x88, 0x86, 0x85, 0x88, 0x8b, 0x8d, 0x8c, 0x87, +0x82, 0x7f, 0x7e, 0x80, 0x80, 0x7e, 0x79, 0x74, 0x71, 0x73, 0x77, 0x7a, +0x7b, 0x7a, 0x78, 0x78, 0x7c, 0x82, 0x87, 0x89, 0x88, 0x86, 0x85, 0x88, +0x8b, 0x8d, 0x8c, 0x88, 0x83, 0x7f, 0x7e, 0x80, 0x81, 0x7e, 0x7a, 0x74, +0x71, 0x72, 0x76, 0x7a, 0x7b, 0x7a, 0x78, 0x78, 0x7c, 0x81, 0x87, 0x89, +0x88, 0x86, 0x85, 0x87, 0x8a, 0x8d, 0x8c, 0x88, 0x83, 0x7f, 0x7e, 0x80, +0x81, 0x7f, 0x7b, 0x75, 0x72, 0x72, 0x76, 0x7a, 0x7c, 0x7a, 0x78, 0x78, +0x7b, 0x81, 0x87, 0x89, 0x89, 0x86, 0x85, 0x86, 0x8a, 0x8c, 0x8c, 0x89, +0x84, 0x80, 0x7e, 0x7f, 0x80, 0x7f, 0x7b, 0x76, 0x72, 0x72, 0x75, 0x79, +0x7b, 0x7b, 0x79, 0x78, 0x7b, 0x80, 0x85, 0x89, 0x89, 0x87, 0x85, 0x86, +0x89, 0x8c, 0x8c, 0x89, 0x84, 0x80, 0x7e, 0x7f, 0x80, 0x80, 0x7c, 0x77, +0x73, 0x72, 0x75, 0x79, 0x7b, 0x7b, 0x79, 0x78, 0x7a, 0x7f, 0x85, 0x88, +0x89, 0x87, 0x85, 0x86, 0x88, 0x8b, 0x8c, 0x8a, 0x85, 0x80, 0x7e, 0x7f, +0x80, 0x80, 0x7c, 0x77, 0x73, 0x72, 0x75, 0x79, 0x7b, 0x7b, 0x79, 0x78, +0x7a, 0x7f, 0x84, 0x88, 0x89, 0x87, 0x85, 0x85, 0x88, 0x8b, 0x8c, 0x8a, +0x85, 0x81, 0x7e, 0x7f, 0x80, 0x80, 0x7d, 0x78, 0x74, 0x72, 0x75, 0x78, +0x7b, 0x7c, 0x7a, 0x78, 0x7a, 0x7e, 0x84, 0x88, 0x89, 0x87, 0x85, 0x85, +0x87, 0x8b, 0x8c, 0x8a, 0x86, 0x81, 0x7e, 0x7f, 0x80, 0x80, 0x7e, 0x79, +0x74, 0x72, 0x74, 0x78, 0x7b, 0x7c, 0x7a, 0x78, 0x79, 0x7d, 0x83, 0x87, +0x89, 0x87, 0x85, 0x85, 0x87, 0x8a, 0x8c, 0x8b, 0x86, 0x81, 0x7f, 0x7f, +0x80, 0x80, 0x7e, 0x79, 0x75, 0x73, 0x74, 0x78, 0x7b, 0x7c, 0x7a, 0x79, +0x79, 0x7d, 0x82, 0x87, 0x88, 0x87, 0x85, 0x84, 0x87, 0x8a, 0x8c, 0x8b, +0x87, 0x82, 0x7f, 0x7e, 0x7f, 0x80, 0x7e, 0x7a, 0x75, 0x73, 0x74, 0x78, +0x7b, 0x7c, 0x7b, 0x79, 0x79, 0x7c, 0x82, 0x86, 0x89, 0x88, 0x85, 0x84, +0x86, 0x89, 0x8c, 0x8b, 0x87, 0x82, 0x7f, 0x7e, 0x80, 0x81, 0x7f, 0x7b, +0x76, 0x73, 0x74, 0x77, 0x7b, 0x7c, 0x7b, 0x79, 0x79, 0x7c, 0x81, 0x86, +0x89, 0x88, 0x85, 0x84, 0x86, 0x89, 0x8c, 0x8b, 0x88, 0x83, 0x7f, 0x7e, +0x7f, 0x81, 0x7f, 0x7b, 0x76, 0x73, 0x73, 0x76, 0x7a, 0x7c, 0x7b, 0x79, +0x79, 0x7b, 0x80, 0x86, 0x88, 0x88, 0x86, 0x84, 0x85, 0x89, 0x8b, 0x8b, +0x88, 0x83, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x7c, 0x77, 0x73, 0x73, 0x76, +0x7a, 0x7c, 0x7b, 0x79, 0x79, 0x7b, 0x80, 0x85, 0x88, 0x88, 0x86, 0x84, +0x85, 0x88, 0x8b, 0x8b, 0x89, 0x84, 0x80, 0x7e, 0x7f, 0x80, 0x80, 0x7c, +0x77, 0x74, 0x73, 0x76, 0x7a, 0x7c, 0x7c, 0x7a, 0x79, 0x7a, 0x7f, 0x84, +0x88, 0x88, 0x86, 0x84, 0x85, 0x88, 0x8b, 0x8c, 0x89, 0x84, 0x80, 0x7e, +0x7f, 0x81, 0x80, 0x7d, 0x78, 0x75, 0x74, 0x76, 0x79, 0x7c, 0x7c, 0x7a, +0x79, 0x7a, 0x7e, 0x83, 0x87, 0x88, 0x86, 0x84, 0x85, 0x87, 0x8a, 0x8b, +0x89, 0x85, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x7a, 0x76, 0x74, 0x76, +0x79, 0x7c, 0x7c, 0x7a, 0x79, 0x7a, 0x7d, 0x82, 0x86, 0x87, 0x86, 0x85, +0x84, 0x86, 0x89, 0x8b, 0x8a, 0x86, 0x82, 0x7f, 0x7f, 0x80, 0x81, 0x7f, +0x7b, 0x77, 0x75, 0x76, 0x78, 0x7b, 0x7c, 0x7b, 0x79, 0x79, 0x7c, 0x81, +0x85, 0x87, 0x86, 0x85, 0x84, 0x86, 0x88, 0x8a, 0x8a, 0x87, 0x83, 0x80, +0x7f, 0x80, 0x81, 0x7f, 0x7c, 0x78, 0x75, 0x75, 0x78, 0x7b, 0x7c, 0x7b, +0x7a, 0x79, 0x7c, 0x80, 0x84, 0x86, 0x86, 0x85, 0x84, 0x85, 0x88, 0x8a, +0x8a, 0x87, 0x83, 0x80, 0x7f, 0x80, 0x81, 0x7f, 0x7c, 0x78, 0x76, 0x76, +0x78, 0x7b, 0x7c, 0x7b, 0x7a, 0x79, 0x7c, 0x80, 0x84, 0x86, 0x86, 0x85, +0x84, 0x85, 0x87, 0x89, 0x8a, 0x87, 0x84, 0x80, 0x7f, 0x80, 0x81, 0x80, +0x7d, 0x79, 0x76, 0x75, 0x78, 0x7a, 0x7c, 0x7c, 0x7a, 0x7a, 0x7b, 0x7f, +0x83, 0x86, 0x86, 0x85, 0x84, 0x84, 0x87, 0x89, 0x8a, 0x87, 0x84, 0x80, +0x7f, 0x80, 0x81, 0x80, 0x7d, 0x79, 0x76, 0x76, 0x78, 0x7a, 0x7c, 0x7c, +0x7a, 0x7a, 0x7b, 0x7f, 0x83, 0x86, 0x86, 0x85, 0x84, 0x84, 0x87, 0x89, +0x8a, 0x88, 0x84, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x7a, 0x77, 0x76, +0x77, 0x7a, 0x7c, 0x7c, 0x7b, 0x7a, 0x7b, 0x7e, 0x82, 0x85, 0x86, 0x85, +0x84, 0x84, 0x86, 0x88, 0x89, 0x88, 0x85, 0x81, 0x7f, 0x7f, 0x80, 0x80, +0x7e, 0x7a, 0x77, 0x76, 0x77, 0x7a, 0x7c, 0x7c, 0x7b, 0x7a, 0x7b, 0x7e, +0x82, 0x85, 0x86, 0x85, 0x84, 0x84, 0x86, 0x88, 0x89, 0x88, 0x85, 0x82, +0x7f, 0x7f, 0x80, 0x81, 0x7f, 0x7b, 0x78, 0x76, 0x77, 0x79, 0x7c, 0x7c, +0x7b, 0x7a, 0x7b, 0x7d, 0x81, 0x84, 0x86, 0x85, 0x84, 0x84, 0x85, 0x87, +0x89, 0x88, 0x85, 0x82, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7c, 0x78, 0x76, +0x77, 0x79, 0x7c, 0x7c, 0x7c, 0x7a, 0x7b, 0x7d, 0x81, 0x84, 0x86, 0x85, +0x84, 0x84, 0x85, 0x87, 0x88, 0x88, 0x86, 0x82, 0x80, 0x7f, 0x80, 0x80, +0x7f, 0x7c, 0x79, 0x77, 0x77, 0x79, 0x7b, 0x7c, 0x7c, 0x7b, 0x7b, 0x7d, +0x80, 0x84, 0x85, 0x85, 0x84, 0x83, 0x84, 0x86, 0x88, 0x88, 0x86, 0x83, +0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7d, 0x79, 0x77, 0x77, 0x79, 0x7b, 0x7d, +0x7c, 0x7b, 0x7a, 0x7c, 0x80, 0x83, 0x85, 0x85, 0x84, 0x83, 0x84, 0x86, +0x88, 0x88, 0x86, 0x83, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7d, 0x7a, 0x77, +0x77, 0x79, 0x7b, 0x7c, 0x7c, 0x7b, 0x7b, 0x7c, 0x7f, 0x83, 0x85, 0x85, +0x84, 0x83, 0x84, 0x86, 0x88, 0x88, 0x87, 0x83, 0x80, 0x7f, 0x7f, 0x80, +0x80, 0x7e, 0x7a, 0x78, 0x77, 0x79, 0x7b, 0x7d, 0x7c, 0x7b, 0x7b, 0x7c, +0x7f, 0x82, 0x85, 0x85, 0x85, 0x83, 0x84, 0x86, 0x87, 0x88, 0x87, 0x84, +0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x7b, 0x78, 0x77, 0x78, 0x7b, 0x7c, +0x7d, 0x7c, 0x7b, 0x7c, 0x7f, 0x82, 0x85, 0x86, 0x85, 0x84, 0x84, 0x85, +0x87, 0x88, 0x87, 0x84, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x7b, 0x78, +0x77, 0x78, 0x7a, 0x7c, 0x7d, 0x7c, 0x7b, 0x7c, 0x7e, 0x82, 0x85, 0x86, +0x85, 0x84, 0x84, 0x85, 0x87, 0x88, 0x87, 0x84, 0x81, 0x7f, 0x7f, 0x7f, +0x80, 0x7e, 0x7c, 0x79, 0x77, 0x78, 0x7a, 0x7c, 0x7d, 0x7c, 0x7b, 0x7c, +0x7e, 0x81, 0x84, 0x85, 0x85, 0x84, 0x84, 0x84, 0x86, 0x88, 0x87, 0x85, +0x82, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7c, 0x79, 0x77, 0x77, 0x79, 0x7b, +0x7c, 0x7c, 0x7b, 0x7b, 0x7d, 0x80, 0x83, 0x85, 0x86, 0x85, 0x84, 0x84, +0x86, 0x88, 0x88, 0x86, 0x83, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7d, 0x7a, +0x77, 0x77, 0x78, 0x7b, 0x7c, 0x7c, 0x7b, 0x7b, 0x7c, 0x7f, 0x83, 0x85, +0x86, 0x85, 0x84, 0x84, 0x86, 0x88, 0x88, 0x86, 0x83, 0x81, 0x7f, 0x7f, +0x80, 0x7f, 0x7d, 0x7a, 0x77, 0x77, 0x78, 0x7a, 0x7c, 0x7c, 0x7c, 0x7b, +0x7c, 0x7f, 0x83, 0x85, 0x86, 0x85, 0x84, 0x84, 0x86, 0x88, 0x88, 0x87, +0x84, 0x81, 0x7f, 0x7f, 0x7f, 0x7f, 0x7d, 0x7a, 0x77, 0x76, 0x77, 0x7a, +0x7c, 0x7d, 0x7c, 0x7b, 0x7c, 0x7f, 0x82, 0x85, 0x86, 0x85, 0x84, 0x84, +0x85, 0x87, 0x88, 0x87, 0x84, 0x81, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7b, +0x77, 0x76, 0x77, 0x7a, 0x7c, 0x7d, 0x7c, 0x7b, 0x7c, 0x7e, 0x82, 0x85, +0x86, 0x86, 0x84, 0x84, 0x85, 0x87, 0x88, 0x88, 0x85, 0x81, 0x7f, 0x7e, +0x7f, 0x7f, 0x7e, 0x7b, 0x78, 0x76, 0x77, 0x79, 0x7c, 0x7d, 0x7c, 0x7b, +0x7c, 0x7e, 0x82, 0x85, 0x87, 0x86, 0x85, 0x84, 0x85, 0x87, 0x88, 0x88, +0x85, 0x82, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7b, 0x78, 0x76, 0x76, 0x79, +0x7b, 0x7d, 0x7c, 0x7b, 0x7b, 0x7d, 0x81, 0x85, 0x87, 0x86, 0x85, 0x84, +0x85, 0x87, 0x88, 0x88, 0x86, 0x82, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7c, +0x78, 0x76, 0x76, 0x78, 0x7b, 0x7d, 0x7d, 0x7c, 0x7b, 0x7d, 0x81, 0x85, +0x87, 0x87, 0x85, 0x84, 0x85, 0x87, 0x88, 0x88, 0x86, 0x82, 0x7f, 0x7e, +0x7f, 0x7f, 0x7e, 0x7c, 0x78, 0x76, 0x76, 0x78, 0x7b, 0x7d, 0x7c, 0x7b, +0x7b, 0x7d, 0x81, 0x85, 0x87, 0x87, 0x85, 0x84, 0x85, 0x87, 0x89, 0x89, +0x86, 0x83, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7c, 0x78, 0x76, 0x76, 0x78, +0x7a, 0x7c, 0x7c, 0x7b, 0x7b, 0x7d, 0x80, 0x84, 0x87, 0x87, 0x86, 0x85, +0x85, 0x87, 0x88, 0x89, 0x87, 0x83, 0x80, 0x7e, 0x7e, 0x7f, 0x7e, 0x7c, +0x79, 0x76, 0x75, 0x77, 0x7a, 0x7c, 0x7c, 0x7c, 0x7b, 0x7c, 0x80, 0x84, +0x87, 0x87, 0x86, 0x85, 0x85, 0x87, 0x88, 0x89, 0x87, 0x84, 0x80, 0x7e, +0x7e, 0x7f, 0x7f, 0x7d, 0x79, 0x76, 0x75, 0x76, 0x79, 0x7c, 0x7c, 0x7c, +0x7b, 0x7c, 0x7f, 0x83, 0x87, 0x88, 0x87, 0x85, 0x85, 0x87, 0x89, 0x89, +0x88, 0x84, 0x80, 0x7e, 0x7e, 0x7f, 0x7e, 0x7d, 0x79, 0x76, 0x75, 0x76, +0x79, 0x7b, 0x7c, 0x7c, 0x7b, 0x7c, 0x7f, 0x83, 0x87, 0x88, 0x87, 0x85, +0x85, 0x86, 0x88, 0x89, 0x88, 0x85, 0x81, 0x7e, 0x7e, 0x7e, 0x7f, 0x7d, +0x7a, 0x76, 0x74, 0x76, 0x78, 0x7b, 0x7c, 0x7c, 0x7b, 0x7b, 0x7e, 0x83, +0x86, 0x88, 0x87, 0x86, 0x85, 0x86, 0x88, 0x8a, 0x88, 0x85, 0x81, 0x7e, +0x7e, 0x7e, 0x7f, 0x7d, 0x7a, 0x76, 0x74, 0x75, 0x78, 0x7b, 0x7c, 0x7c, +0x7b, 0x7b, 0x7e, 0x82, 0x86, 0x88, 0x87, 0x86, 0x85, 0x86, 0x88, 0x89, +0x89, 0x86, 0x82, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7a, 0x77, 0x75, 0x75, +0x78, 0x7b, 0x7c, 0x7c, 0x7b, 0x7b, 0x7d, 0x81, 0x85, 0x87, 0x87, 0x86, +0x85, 0x85, 0x87, 0x89, 0x89, 0x86, 0x83, 0x80, 0x7e, 0x7e, 0x7f, 0x7e, +0x7b, 0x78, 0x75, 0x75, 0x77, 0x7a, 0x7c, 0x7c, 0x7b, 0x7b, 0x7d, 0x80, +0x84, 0x87, 0x87, 0x86, 0x85, 0x85, 0x87, 0x89, 0x89, 0x87, 0x84, 0x80, +0x7e, 0x7e, 0x7f, 0x7f, 0x7c, 0x79, 0x76, 0x75, 0x77, 0x79, 0x7c, 0x7c, +0x7b, 0x7b, 0x7c, 0x7f, 0x83, 0x87, 0x87, 0x86, 0x85, 0x85, 0x87, 0x89, +0x89, 0x88, 0x84, 0x81, 0x7e, 0x7e, 0x7f, 0x7f, 0x7d, 0x79, 0x76, 0x75, +0x76, 0x79, 0x7b, 0x7c, 0x7b, 0x7b, 0x7c, 0x7f, 0x83, 0x87, 0x88, 0x87, +0x85, 0x85, 0x87, 0x89, 0x89, 0x88, 0x85, 0x81, 0x7f, 0x7e, 0x7f, 0x7f, +0x7d, 0x7a, 0x76, 0x75, 0x76, 0x78, 0x7b, 0x7c, 0x7b, 0x7b, 0x7b, 0x7e, +0x83, 0x86, 0x88, 0x87, 0x85, 0x85, 0x86, 0x88, 0x8a, 0x89, 0x85, 0x81, +0x7f, 0x7e, 0x7f, 0x7f, 0x7d, 0x7a, 0x76, 0x75, 0x75, 0x78, 0x7b, 0x7c, +0x7b, 0x7b, 0x7b, 0x7e, 0x82, 0x86, 0x88, 0x87, 0x86, 0x85, 0x86, 0x88, +0x8a, 0x89, 0x86, 0x82, 0x7f, 0x7e, 0x7f, 0x7f, 0x7d, 0x7a, 0x77, 0x75, +0x75, 0x78, 0x7a, 0x7c, 0x7b, 0x7a, 0x7b, 0x7d, 0x81, 0x85, 0x87, 0x87, +0x86, 0x85, 0x86, 0x88, 0x8a, 0x89, 0x87, 0x83, 0x7f, 0x7e, 0x7e, 0x7f, +0x7e, 0x7b, 0x77, 0x75, 0x75, 0x77, 0x7a, 0x7c, 0x7b, 0x7b, 0x7b, 0x7d, +0x81, 0x85, 0x87, 0x87, 0x86, 0x85, 0x86, 0x88, 0x8a, 0x89, 0x87, 0x83, +0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7b, 0x78, 0x75, 0x75, 0x77, 0x79, 0x7b, +0x7b, 0x7b, 0x7a, 0x7c, 0x80, 0x85, 0x87, 0x88, 0x87, 0x85, 0x86, 0x88, +0x8a, 0x8a, 0x88, 0x84, 0x80, 0x7e, 0x7e, 0x7f, 0x7e, 0x7b, 0x78, 0x75, +0x74, 0x76, 0x79, 0x7b, 0x7b, 0x7b, 0x7a, 0x7c, 0x80, 0x84, 0x87, 0x88, +0x87, 0x86, 0x86, 0x88, 0x8a, 0x8a, 0x88, 0x84, 0x81, 0x7e, 0x7e, 0x7f, +0x7e, 0x7c, 0x78, 0x75, 0x74, 0x76, 0x79, 0x7b, 0x7b, 0x7b, 0x7a, 0x7c, +0x7f, 0x84, 0x87, 0x88, 0x87, 0x86, 0x86, 0x87, 0x89, 0x8a, 0x89, 0x85, +0x81, 0x7e, 0x7e, 0x7f, 0x7e, 0x7c, 0x79, 0x75, 0x74, 0x75, 0x78, 0x7b, +0x7c, 0x7b, 0x7a, 0x7b, 0x7f, 0x83, 0x87, 0x88, 0x87, 0x86, 0x86, 0x87, +0x89, 0x8a, 0x89, 0x86, 0x82, 0x7f, 0x7e, 0x7f, 0x7e, 0x7d, 0x79, 0x75, +0x74, 0x75, 0x78, 0x7b, 0x7c, 0x7b, 0x7a, 0x7b, 0x7e, 0x83, 0x87, 0x88, +0x88, 0x86, 0x86, 0x87, 0x89, 0x8b, 0x8a, 0x87, 0x82, 0x7f, 0x7e, 0x7f, +0x7f, 0x7d, 0x79, 0x76, 0x74, 0x74, 0x77, 0x7a, 0x7b, 0x7b, 0x7a, 0x7b, +0x7e, 0x82, 0x86, 0x88, 0x88, 0x86, 0x86, 0x87, 0x89, 0x8b, 0x8a, 0x87, +0x83, 0x80, 0x7e, 0x7f, 0x7f, 0x7d, 0x7a, 0x76, 0x74, 0x74, 0x77, 0x7a, +0x7b, 0x7b, 0x7a, 0x7a, 0x7d, 0x81, 0x86, 0x88, 0x88, 0x86, 0x86, 0x87, +0x89, 0x8b, 0x8a, 0x87, 0x83, 0x80, 0x7e, 0x7f, 0x7f, 0x7d, 0x7a, 0x76, +0x74, 0x74, 0x76, 0x79, 0x7b, 0x7b, 0x7a, 0x7a, 0x7c, 0x81, 0x85, 0x88, +0x88, 0x87, 0x86, 0x87, 0x89, 0x8b, 0x8b, 0x88, 0x84, 0x80, 0x7e, 0x7f, +0x7f, 0x7e, 0x7b, 0x77, 0x74, 0x73, 0x76, 0x79, 0x7b, 0x7b, 0x7a, 0x7a, +0x7c, 0x80, 0x85, 0x88, 0x88, 0x87, 0x86, 0x87, 0x89, 0x8b, 0x8b, 0x88, +0x84, 0x80, 0x7e, 0x7f, 0x7f, 0x7e, 0x7b, 0x77, 0x74, 0x73, 0x75, 0x78, +0x7b, 0x7b, 0x7a, 0x79, 0x7b, 0x7f, 0x84, 0x87, 0x88, 0x87, 0x86, 0x86, +0x88, 0x8a, 0x8b, 0x89, 0x85, 0x81, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x79, +0x75, 0x74, 0x75, 0x78, 0x7b, 0x7b, 0x7a, 0x7a, 0x7b, 0x7e, 0x82, 0x86, +0x87, 0x87, 0x85, 0x85, 0x87, 0x89, 0x8a, 0x89, 0x85, 0x82, 0x7f, 0x7f, +0x7f, 0x7f, 0x7d, 0x7a, 0x77, 0x75, 0x76, 0x78, 0x7b, 0x7c, 0x7b, 0x7a, +0x7b, 0x7e, 0x82, 0x85, 0x87, 0x86, 0x85, 0x85, 0x86, 0x88, 0x89, 0x88, +0x85, 0x82, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7b, 0x78, 0x76, 0x76, 0x78, +0x7b, 0x7c, 0x7c, 0x7b, 0x7b, 0x7d, 0x81, 0x85, 0x87, 0x86, 0x85, 0x85, +0x86, 0x87, 0x89, 0x89, 0x86, 0x83, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7b, +0x78, 0x76, 0x76, 0x78, 0x7a, 0x7c, 0x7c, 0x7a, 0x7b, 0x7d, 0x81, 0x84, +0x87, 0x86, 0x85, 0x85, 0x86, 0x88, 0x89, 0x89, 0x87, 0x83, 0x80, 0x7f, +0x7f, 0x7f, 0x7e, 0x7c, 0x78, 0x75, 0x75, 0x77, 0x7a, 0x7c, 0x7b, 0x7a, +0x7a, 0x7c, 0x80, 0x84, 0x87, 0x87, 0x86, 0x85, 0x85, 0x87, 0x89, 0x89, +0x87, 0x84, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x78, 0x76, 0x75, 0x77, +0x7a, 0x7c, 0x7c, 0x7a, 0x7a, 0x7c, 0x7f, 0x84, 0x86, 0x87, 0x86, 0x85, +0x85, 0x87, 0x89, 0x8a, 0x88, 0x84, 0x81, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, +0x79, 0x76, 0x75, 0x76, 0x79, 0x7b, 0x7c, 0x7b, 0x7a, 0x7c, 0x7f, 0x83, +0x86, 0x87, 0x86, 0x85, 0x85, 0x87, 0x89, 0x8a, 0x88, 0x85, 0x81, 0x7f, +0x7f, 0x7f, 0x7f, 0x7d, 0x79, 0x76, 0x75, 0x76, 0x79, 0x7b, 0x7c, 0x7b, +0x7a, 0x7b, 0x7f, 0x83, 0x86, 0x87, 0x87, 0x85, 0x85, 0x87, 0x89, 0x8a, +0x89, 0x85, 0x82, 0x7f, 0x7f, 0x7f, 0x7f, 0x7d, 0x7a, 0x76, 0x74, 0x75, +0x78, 0x7b, 0x7c, 0x7b, 0x7b, 0x7b, 0x7e, 0x82, 0x86, 0x87, 0x87, 0x86, +0x85, 0x87, 0x89, 0x8a, 0x89, 0x86, 0x82, 0x7f, 0x7e, 0x7f, 0x7f, 0x7d, +0x7a, 0x76, 0x75, 0x76, 0x78, 0x7b, 0x7b, 0x7b, 0x7a, 0x7b, 0x7e, 0x82, +0x86, 0x87, 0x87, 0x86, 0x86, 0x87, 0x89, 0x8a, 0x89, 0x86, 0x82, 0x7f, +0x7e, 0x7f, 0x7f, 0x7d, 0x7a, 0x77, 0x75, 0x76, 0x78, 0x7a, 0x7b, 0x7b, +0x7a, 0x7b, 0x7d, 0x81, 0x85, 0x87, 0x87, 0x86, 0x85, 0x86, 0x89, 0x8a, +0x89, 0x86, 0x82, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7b, 0x77, 0x75, 0x75, +0x77, 0x7a, 0x7b, 0x7b, 0x7a, 0x7a, 0x7d, 0x81, 0x85, 0x87, 0x87, 0x86, +0x85, 0x86, 0x89, 0x8a, 0x8a, 0x87, 0x83, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, +0x7b, 0x77, 0x75, 0x75, 0x77, 0x7a, 0x7b, 0x7b, 0x7a, 0x7a, 0x7c, 0x80, +0x84, 0x87, 0x87, 0x86, 0x85, 0x86, 0x88, 0x8a, 0x8a, 0x87, 0x83, 0x80, +0x7f, 0x7f, 0x7f, 0x7e, 0x7b, 0x77, 0x75, 0x75, 0x77, 0x79, 0x7b, 0x7b, +0x7a, 0x7a, 0x7c, 0x80, 0x84, 0x87, 0x87, 0x86, 0x86, 0x86, 0x88, 0x8a, +0x8a, 0x88, 0x84, 0x81, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x78, 0x75, 0x74, +0x76, 0x79, 0x7b, 0x7b, 0x7a, 0x7a, 0x7c, 0x7f, 0x84, 0x87, 0x87, 0x86, +0x85, 0x86, 0x88, 0x8a, 0x8a, 0x88, 0x85, 0x81, 0x7f, 0x7f, 0x7f, 0x7f, +0x7c, 0x78, 0x75, 0x74, 0x76, 0x79, 0x7b, 0x7b, 0x7a, 0x7a, 0x7c, 0x7f, +0x84, 0x87, 0x88, 0x87, 0x85, 0x85, 0x87, 0x89, 0x8a, 0x89, 0x85, 0x81, +0x7f, 0x7e, 0x7f, 0x7f, 0x7d, 0x7a, 0x76, 0x75, 0x76, 0x79, 0x7b, 0x7c, +0x7b, 0x7a, 0x7b, 0x7e, 0x82, 0x85, 0x87, 0x86, 0x85, 0x85, 0x86, 0x88, +0x89, 0x88, 0x85, 0x82, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7b, 0x78, 0x76, +0x77, 0x79, 0x7b, 0x7d, 0x7c, 0x7b, 0x7b, 0x7e, 0x81, 0x84, 0x86, 0x86, +0x85, 0x84, 0x85, 0x86, 0x88, 0x87, 0x85, 0x82, 0x7f, 0x7f, 0x7f, 0x7f, +0x7e, 0x7c, 0x79, 0x77, 0x77, 0x79, 0x7c, 0x7d, 0x7d, 0x7c, 0x7c, 0x7e, +0x81, 0x84, 0x86, 0x86, 0x84, 0x84, 0x84, 0x86, 0x87, 0x87, 0x85, 0x82, +0x80, 0x7e, 0x7f, 0x7f, 0x7e, 0x7c, 0x79, 0x77, 0x77, 0x79, 0x7b, 0x7d, +0x7d, 0x7c, 0x7c, 0x7d, 0x80, 0x84, 0x86, 0x86, 0x85, 0x84, 0x84, 0x86, +0x87, 0x87, 0x85, 0x83, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7c, 0x79, 0x77, +0x77, 0x79, 0x7b, 0x7d, 0x7d, 0x7c, 0x7c, 0x7d, 0x80, 0x84, 0x86, 0x86, +0x85, 0x84, 0x84, 0x86, 0x88, 0x88, 0x86, 0x83, 0x80, 0x7f, 0x7f, 0x7f, +0x7e, 0x7c, 0x7a, 0x77, 0x77, 0x78, 0x7b, 0x7c, 0x7d, 0x7c, 0x7c, 0x7d, +0x80, 0x83, 0x85, 0x86, 0x86, 0x85, 0x85, 0x86, 0x87, 0x88, 0x86, 0x83, +0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7d, 0x7a, 0x78, 0x77, 0x78, 0x7b, 0x7c, +0x7d, 0x7c, 0x7b, 0x7c, 0x7f, 0x83, 0x85, 0x86, 0x86, 0x85, 0x85, 0x86, +0x87, 0x88, 0x87, 0x84, 0x81, 0x7f, 0x7e, 0x7f, 0x7f, 0x7d, 0x7a, 0x78, +0x76, 0x78, 0x7a, 0x7c, 0x7d, 0x7c, 0x7c, 0x7c, 0x7f, 0x82, 0x85, 0x87, +0x86, 0x85, 0x85, 0x85, 0x87, 0x88, 0x87, 0x84, 0x81, 0x7f, 0x7e, 0x7f, +0x7f, 0x7d, 0x7b, 0x78, 0x77, 0x77, 0x79, 0x7c, 0x7d, 0x7c, 0x7c, 0x7d, +0x7f, 0x82, 0x85, 0x86, 0x85, 0x85, 0x84, 0x85, 0x87, 0x88, 0x87, 0x85, +0x81, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7b, 0x78, 0x77, 0x77, 0x79, 0x7c, +0x7d, 0x7c, 0x7c, 0x7c, 0x7e, 0x81, 0x85, 0x86, 0x86, 0x85, 0x84, 0x85, +0x86, 0x88, 0x87, 0x85, 0x82, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7c, 0x79, +0x77, 0x77, 0x79, 0x7b, 0x7d, 0x7d, 0x7c, 0x7c, 0x7e, 0x81, 0x84, 0x86, +0x86, 0x84, 0x84, 0x85, 0x87, 0x88, 0x88, 0x86, 0x82, 0x80, 0x7e, 0x7e, +0x7f, 0x7e, 0x7c, 0x79, 0x77, 0x77, 0x78, 0x7b, 0x7d, 0x7d, 0x7d, 0x7c, +0x7d, 0x80, 0x83, 0x86, 0x87, 0x86, 0x85, 0x85, 0x86, 0x87, 0x88, 0x86, +0x83, 0x80, 0x7e, 0x7e, 0x7e, 0x7e, 0x7c, 0x7a, 0x77, 0x76, 0x78, 0x7a, +0x7c, 0x7d, 0x7d, 0x7c, 0x7d, 0x80, 0x83, 0x86, 0x87, 0x86, 0x85, 0x85, +0x86, 0x87, 0x87, 0x86, 0x84, 0x81, 0x7e, 0x7e, 0x7f, 0x7e, 0x7d, 0x7a, +0x77, 0x76, 0x78, 0x7a, 0x7c, 0x7d, 0x7c, 0x7c, 0x7d, 0x7f, 0x83, 0x86, +0x87, 0x86, 0x85, 0x85, 0x86, 0x88, 0x88, 0x87, 0x84, 0x81, 0x7e, 0x7e, +0x7e, 0x7e, 0x7d, 0x7a, 0x77, 0x76, 0x77, 0x79, 0x7c, 0x7c, 0x7c, 0x7c, +0x7c, 0x7f, 0x83, 0x85, 0x87, 0x86, 0x85, 0x84, 0x86, 0x87, 0x88, 0x88, +0x85, 0x81, 0x7f, 0x7e, 0x7e, 0x7f, 0x7d, 0x7a, 0x78, 0x76, 0x77, 0x79, +0x7b, 0x7c, 0x7c, 0x7b, 0x7c, 0x7e, 0x82, 0x85, 0x87, 0x86, 0x85, 0x84, +0x86, 0x87, 0x88, 0x88, 0x85, 0x82, 0x80, 0x7f, 0x7f, 0x7f, 0x7d, 0x7b, +0x78, 0x76, 0x76, 0x79, 0x7b, 0x7c, 0x7c, 0x7b, 0x7b, 0x7e, 0x81, 0x84, +0x86, 0x86, 0x85, 0x84, 0x85, 0x86, 0x88, 0x87, 0x85, 0x83, 0x80, 0x7f, +0x7f, 0x7f, 0x7e, 0x7d, 0x7a, 0x78, 0x78, 0x79, 0x7b, 0x7d, 0x7c, 0x7b, +0x7b, 0x7d, 0x7f, 0x83, 0x85, 0x85, 0x84, 0x84, 0x84, 0x85, 0x86, 0x86, +0x85, 0x83, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7b, 0x79, 0x79, 0x7a, +0x7c, 0x7d, 0x7d, 0x7c, 0x7c, 0x7d, 0x7f, 0x82, 0x84, 0x84, 0x84, 0x83, +0x83, 0x84, 0x86, 0x86, 0x85, 0x83, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7e, +0x7c, 0x7a, 0x79, 0x7a, 0x7c, 0x7d, 0x7d, 0x7d, 0x7c, 0x7d, 0x7f, 0x82, +0x83, 0x84, 0x84, 0x83, 0x83, 0x84, 0x85, 0x86, 0x85, 0x83, 0x81, 0x80, +0x7f, 0x80, 0x80, 0x7f, 0x7c, 0x7a, 0x79, 0x7a, 0x7c, 0x7d, 0x7e, 0x7d, +0x7c, 0x7c, 0x7e, 0x81, 0x84, 0x85, 0x84, 0x83, 0x82, 0x83, 0x85, 0x86, +0x85, 0x83, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7d, 0x7a, 0x79, 0x7a, +0x7c, 0x7d, 0x7e, 0x7d, 0x7c, 0x7c, 0x7e, 0x81, 0x84, 0x85, 0x84, 0x83, +0x82, 0x83, 0x85, 0x86, 0x86, 0x84, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, +0x7d, 0x7a, 0x79, 0x79, 0x7b, 0x7d, 0x7e, 0x7d, 0x7c, 0x7c, 0x7e, 0x81, +0x83, 0x84, 0x84, 0x83, 0x82, 0x83, 0x85, 0x86, 0x86, 0x84, 0x81, 0x7f, +0x7f, 0x7f, 0x80, 0x80, 0x7d, 0x7a, 0x79, 0x79, 0x7a, 0x7d, 0x7e, 0x7d, +0x7c, 0x7c, 0x7d, 0x80, 0x83, 0x85, 0x85, 0x83, 0x82, 0x83, 0x85, 0x86, +0x86, 0x85, 0x82, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x7b, 0x79, 0x78, +0x7a, 0x7d, 0x7e, 0x7e, 0x7d, 0x7c, 0x7d, 0x7f, 0x82, 0x85, 0x85, 0x84, +0x82, 0x83, 0x84, 0x85, 0x86, 0x85, 0x82, 0x80, 0x7f, 0x7f, 0x81, 0x80, +0x7e, 0x7b, 0x79, 0x78, 0x7a, 0x7c, 0x7e, 0x7e, 0x7c, 0x7b, 0x7c, 0x7f, +0x82, 0x85, 0x85, 0x83, 0x82, 0x82, 0x84, 0x86, 0x87, 0x85, 0x83, 0x80, +0x7f, 0x80, 0x81, 0x80, 0x7f, 0x7c, 0x79, 0x78, 0x7a, 0x7c, 0x7e, 0x7e, +0x7c, 0x7b, 0x7c, 0x7e, 0x82, 0x84, 0x84, 0x83, 0x82, 0x82, 0x83, 0x86, +0x87, 0x86, 0x84, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x7f, 0x7c, 0x79, 0x79, +0x79, 0x7c, 0x7e, 0x7e, 0x7c, 0x7c, 0x7c, 0x7e, 0x82, 0x84, 0x85, 0x84, +0x82, 0x81, 0x83, 0x85, 0x87, 0x86, 0x84, 0x81, 0x7f, 0x7f, 0x80, 0x81, +0x80, 0x7d, 0x7a, 0x78, 0x79, 0x7c, 0x7e, 0x7e, 0x7d, 0x7b, 0x7b, 0x7e, +0x81, 0x84, 0x85, 0x84, 0x82, 0x82, 0x83, 0x85, 0x87, 0x86, 0x84, 0x81, +0x7f, 0x7e, 0x80, 0x81, 0x80, 0x7d, 0x7a, 0x78, 0x79, 0x7c, 0x7e, 0x7e, +0x7d, 0x7b, 0x7b, 0x7d, 0x81, 0x84, 0x85, 0x84, 0x82, 0x82, 0x83, 0x85, +0x87, 0x86, 0x84, 0x81, 0x7f, 0x7e, 0x80, 0x81, 0x80, 0x7d, 0x7a, 0x78, +0x79, 0x7b, 0x7d, 0x7e, 0x7d, 0x7c, 0x7b, 0x7d, 0x80, 0x84, 0x85, 0x84, +0x83, 0x82, 0x83, 0x85, 0x87, 0x86, 0x84, 0x81, 0x7f, 0x7f, 0x80, 0x80, +0x80, 0x7d, 0x7a, 0x78, 0x79, 0x7b, 0x7d, 0x7e, 0x7d, 0x7c, 0x7b, 0x7d, +0x80, 0x84, 0x85, 0x85, 0x83, 0x82, 0x83, 0x85, 0x87, 0x87, 0x85, 0x82, +0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x7e, 0x7a, 0x78, 0x78, 0x7a, 0x7d, 0x7e, +0x7d, 0x7c, 0x7b, 0x7c, 0x80, 0x83, 0x85, 0x85, 0x84, 0x82, 0x83, 0x84, +0x86, 0x87, 0x85, 0x82, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7e, 0x7c, 0x79, +0x79, 0x7a, 0x7d, 0x7e, 0x7e, 0x7d, 0x7b, 0x7c, 0x7f, 0x82, 0x84, 0x85, +0x83, 0x81, 0x81, 0x82, 0x84, 0x86, 0x85, 0x83, 0x80, 0x7f, 0x7f, 0x81, +0x81, 0x80, 0x7e, 0x7b, 0x7a, 0x7b, 0x7d, 0x7f, 0x7f, 0x7e, 0x7c, 0x7c, +0x7e, 0x81, 0x83, 0x84, 0x82, 0x81, 0x80, 0x81, 0x84, 0x85, 0x85, 0x83, +0x80, 0x7f, 0x7f, 0x81, 0x81, 0x80, 0x7e, 0x7b, 0x7a, 0x7b, 0x7d, 0x7f, +0x7f, 0x7e, 0x7c, 0x7c, 0x7d, 0x80, 0x83, 0x84, 0x83, 0x81, 0x80, 0x81, +0x83, 0x85, 0x85, 0x83, 0x80, 0x7e, 0x7f, 0x80, 0x82, 0x81, 0x7f, 0x7b, +0x7a, 0x7b, 0x7d, 0x7f, 0x7f, 0x7e, 0x7d, 0x7c, 0x7d, 0x80, 0x83, 0x83, +0x83, 0x81, 0x80, 0x81, 0x83, 0x84, 0x85, 0x83, 0x81, 0x7f, 0x7f, 0x80, +0x81, 0x80, 0x7e, 0x7c, 0x7b, 0x7b, 0x7d, 0x7f, 0x7f, 0x7e, 0x7d, 0x7c, +0x7d, 0x80, 0x82, 0x83, 0x83, 0x81, 0x81, 0x81, 0x83, 0x84, 0x85, 0x83, +0x81, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x7f, 0x7c, 0x7b, 0x7b, 0x7d, 0x7e, +0x7f, 0x7e, 0x7d, 0x7c, 0x7d, 0x80, 0x82, 0x84, 0x83, 0x81, 0x80, 0x81, +0x83, 0x84, 0x85, 0x83, 0x81, 0x7f, 0x7e, 0x80, 0x81, 0x81, 0x7f, 0x7d, +0x7a, 0x7a, 0x7c, 0x7e, 0x80, 0x7f, 0x7d, 0x7c, 0x7d, 0x80, 0x82, 0x84, +0x83, 0x82, 0x81, 0x80, 0x82, 0x84, 0x85, 0x84, 0x81, 0x7f, 0x7e, 0x7f, +0x81, 0x81, 0x7f, 0x7d, 0x7a, 0x7a, 0x7c, 0x7f, 0x80, 0x80, 0x7e, 0x7d, +0x7d, 0x7f, 0x82, 0x84, 0x84, 0x82, 0x80, 0x80, 0x82, 0x84, 0x85, 0x84, +0x82, 0x7f, 0x7e, 0x7e, 0x80, 0x80, 0x7f, 0x7d, 0x7b, 0x7a, 0x7c, 0x7e, +0x80, 0x80, 0x7f, 0x7d, 0x7d, 0x7f, 0x82, 0x84, 0x84, 0x83, 0x81, 0x80, +0x82, 0x83, 0x85, 0x84, 0x82, 0x7f, 0x7d, 0x7e, 0x7f, 0x80, 0x7f, 0x7d, +0x7b, 0x7a, 0x7b, 0x7e, 0x80, 0x80, 0x7f, 0x7d, 0x7d, 0x7f, 0x82, 0x84, +0x85, 0x83, 0x81, 0x81, 0x81, 0x83, 0x85, 0x84, 0x82, 0x7f, 0x7d, 0x7d, +0x7f, 0x80, 0x80, 0x7d, 0x7b, 0x7a, 0x7b, 0x7d, 0x7f, 0x80, 0x7f, 0x7d, +0x7d, 0x7f, 0x82, 0x84, 0x85, 0x84, 0x82, 0x81, 0x82, 0x83, 0x85, 0x84, +0x82, 0x7f, 0x7d, 0x7d, 0x7e, 0x80, 0x80, 0x7d, 0x7b, 0x79, 0x7a, 0x7d, +0x7f, 0x80, 0x7f, 0x7e, 0x7d, 0x7e, 0x81, 0x84, 0x85, 0x84, 0x82, 0x81, +0x82, 0x83, 0x85, 0x85, 0x83, 0x80, 0x7e, 0x7d, 0x7e, 0x80, 0x7f, 0x7d, +0x7b, 0x7a, 0x7a, 0x7c, 0x7e, 0x80, 0x7f, 0x7e, 0x7d, 0x7e, 0x81, 0x84, +0x86, 0x85, 0x83, 0x81, 0x81, 0x83, 0x85, 0x85, 0x83, 0x80, 0x7e, 0x7d, +0x7e, 0x7f, 0x7f, 0x7e, 0x7b, 0x79, 0x79, 0x7c, 0x7e, 0x80, 0x80, 0x7e, +0x7d, 0x7e, 0x81, 0x84, 0x86, 0x85, 0x83, 0x81, 0x81, 0x83, 0x85, 0x85, +0x83, 0x80, 0x7e, 0x7d, 0x7e, 0x7f, 0x80, 0x7e, 0x7b, 0x79, 0x79, 0x7c, +0x7e, 0x7f, 0x7f, 0x7e, 0x7d, 0x7e, 0x80, 0x84, 0x86, 0x85, 0x84, 0x82, +0x81, 0x83, 0x85, 0x85, 0x84, 0x81, 0x7e, 0x7d, 0x7e, 0x7f, 0x80, 0x7e, +0x7b, 0x79, 0x79, 0x7b, 0x7e, 0x80, 0x7f, 0x7e, 0x7d, 0x7d, 0x80, 0x84, +0x86, 0x85, 0x84, 0x81, 0x81, 0x83, 0x85, 0x86, 0x85, 0x81, 0x7e, 0x7d, +0x7d, 0x7f, 0x80, 0x7e, 0x7c, 0x79, 0x78, 0x7a, 0x7d, 0x7f, 0x80, 0x7f, +0x7d, 0x7d, 0x7f, 0x83, 0x85, 0x86, 0x84, 0x82, 0x81, 0x82, 0x84, 0x85, +0x84, 0x82, 0x7f, 0x7d, 0x7d, 0x7f, 0x80, 0x7f, 0x7d, 0x7b, 0x7a, 0x7b, +0x7e, 0x80, 0x81, 0x80, 0x7e, 0x7d, 0x7f, 0x82, 0x84, 0x85, 0x83, 0x81, +0x80, 0x80, 0x82, 0x83, 0x83, 0x81, 0x7f, 0x7d, 0x7d, 0x7f, 0x80, 0x80, +0x7e, 0x7c, 0x7b, 0x7c, 0x7e, 0x80, 0x81, 0x80, 0x7e, 0x7e, 0x7f, 0x82, +0x84, 0x85, 0x83, 0x81, 0x80, 0x80, 0x82, 0x83, 0x83, 0x81, 0x7f, 0x7d, +0x7d, 0x7e, 0x7f, 0x80, 0x7e, 0x7c, 0x7b, 0x7c, 0x7e, 0x80, 0x81, 0x80, +0x7e, 0x7e, 0x7f, 0x82, 0x84, 0x85, 0x84, 0x82, 0x80, 0x80, 0x82, 0x83, +0x83, 0x82, 0x7f, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x7e, 0x7b, 0x7a, 0x7b, +0x7d, 0x80, 0x81, 0x80, 0x7f, 0x7e, 0x7f, 0x82, 0x84, 0x85, 0x84, 0x82, +0x80, 0x81, 0x82, 0x84, 0x84, 0x82, 0x7f, 0x7d, 0x7c, 0x7e, 0x7f, 0x7f, +0x7e, 0x7b, 0x7a, 0x7a, 0x7c, 0x7f, 0x81, 0x80, 0x7f, 0x7e, 0x7f, 0x82, +0x84, 0x86, 0x85, 0x83, 0x81, 0x81, 0x82, 0x84, 0x84, 0x82, 0x7f, 0x7d, +0x7c, 0x7d, 0x7e, 0x7f, 0x7e, 0x7b, 0x7a, 0x7a, 0x7c, 0x7f, 0x81, 0x81, +0x7f, 0x7e, 0x7f, 0x81, 0x84, 0x86, 0x85, 0x83, 0x81, 0x81, 0x82, 0x84, +0x85, 0x83, 0x80, 0x7d, 0x7c, 0x7d, 0x7f, 0x7f, 0x7e, 0x7c, 0x79, 0x79, +0x7c, 0x7f, 0x81, 0x81, 0x80, 0x7e, 0x7e, 0x81, 0x84, 0x87, 0x86, 0x83, +0x81, 0x80, 0x82, 0x84, 0x85, 0x83, 0x80, 0x7d, 0x7b, 0x7c, 0x7e, 0x80, +0x7f, 0x7c, 0x7a, 0x79, 0x7b, 0x7e, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x81, +0x84, 0x86, 0x86, 0x84, 0x82, 0x81, 0x82, 0x84, 0x85, 0x83, 0x80, 0x7d, +0x7c, 0x7c, 0x7e, 0x80, 0x7f, 0x7c, 0x79, 0x79, 0x7b, 0x7e, 0x81, 0x81, +0x80, 0x7e, 0x7e, 0x80, 0x84, 0x86, 0x87, 0x85, 0x82, 0x81, 0x82, 0x84, +0x85, 0x84, 0x81, 0x7d, 0x7c, 0x7c, 0x7e, 0x7f, 0x7f, 0x7c, 0x79, 0x78, +0x7a, 0x7d, 0x80, 0x81, 0x80, 0x7e, 0x7e, 0x80, 0x84, 0x86, 0x87, 0x85, +0x82, 0x81, 0x82, 0x84, 0x85, 0x84, 0x81, 0x7e, 0x7c, 0x7c, 0x7e, 0x7f, +0x7f, 0x7c, 0x79, 0x78, 0x7a, 0x7d, 0x80, 0x81, 0x80, 0x7e, 0x7e, 0x80, +0x83, 0x87, 0x87, 0x85, 0x83, 0x81, 0x82, 0x84, 0x85, 0x85, 0x82, 0x7e, +0x7c, 0x7c, 0x7d, 0x7f, 0x7f, 0x7c, 0x79, 0x78, 0x79, 0x7c, 0x80, 0x81, +0x80, 0x7e, 0x7e, 0x80, 0x84, 0x87, 0x87, 0x85, 0x83, 0x81, 0x81, 0x83, +0x85, 0x85, 0x83, 0x7f, 0x7c, 0x7b, 0x7d, 0x7f, 0x7f, 0x7d, 0x79, 0x78, +0x79, 0x7c, 0x80, 0x81, 0x81, 0x7f, 0x7e, 0x7f, 0x82, 0x86, 0x88, 0x86, +0x83, 0x81, 0x81, 0x83, 0x85, 0x85, 0x83, 0x7f, 0x7c, 0x7b, 0x7c, 0x7e, +0x7f, 0x7d, 0x7a, 0x78, 0x78, 0x7b, 0x7f, 0x81, 0x81, 0x7f, 0x7e, 0x7e, +0x81, 0x85, 0x88, 0x87, 0x84, 0x82, 0x81, 0x82, 0x85, 0x85, 0x83, 0x7f, +0x7c, 0x7b, 0x7c, 0x7e, 0x7f, 0x7d, 0x7a, 0x78, 0x79, 0x7b, 0x7e, 0x80, +0x80, 0x7f, 0x7e, 0x7f, 0x82, 0x85, 0x87, 0x86, 0x84, 0x82, 0x81, 0x83, +0x85, 0x85, 0x83, 0x7f, 0x7c, 0x7b, 0x7d, 0x7e, 0x7f, 0x7d, 0x7a, 0x78, +0x78, 0x7b, 0x7e, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x82, 0x85, 0x87, 0x87, +0x84, 0x82, 0x82, 0x83, 0x85, 0x86, 0x84, 0x80, 0x7d, 0x7b, 0x7c, 0x7e, +0x7f, 0x7d, 0x7b, 0x78, 0x78, 0x7b, 0x7e, 0x80, 0x81, 0x80, 0x7e, 0x7f, +0x81, 0x84, 0x87, 0x86, 0x84, 0x81, 0x80, 0x81, 0x83, 0x84, 0x83, 0x80, +0x7d, 0x7b, 0x7c, 0x7e, 0x7f, 0x7f, 0x7d, 0x7a, 0x7a, 0x7c, 0x7f, 0x81, +0x82, 0x80, 0x7f, 0x7f, 0x81, 0x84, 0x86, 0x86, 0x84, 0x81, 0x80, 0x81, +0x83, 0x84, 0x83, 0x80, 0x7d, 0x7b, 0x7c, 0x7e, 0x7f, 0x7f, 0x7d, 0x7a, +0x79, 0x7b, 0x7e, 0x81, 0x82, 0x81, 0x7f, 0x7f, 0x80, 0x83, 0x85, 0x86, +0x84, 0x81, 0x80, 0x81, 0x83, 0x84, 0x84, 0x81, 0x7d, 0x7b, 0x7c, 0x7e, +0x7f, 0x7f, 0x7d, 0x7a, 0x79, 0x7b, 0x7e, 0x81, 0x82, 0x81, 0x7f, 0x7e, +0x7f, 0x83, 0x86, 0x87, 0x85, 0x82, 0x80, 0x80, 0x82, 0x84, 0x84, 0x81, +0x7e, 0x7b, 0x7b, 0x7d, 0x7f, 0x80, 0x7e, 0x7b, 0x79, 0x7a, 0x7e, 0x81, +0x82, 0x81, 0x7e, 0x7d, 0x7f, 0x82, 0x86, 0x87, 0x85, 0x82, 0x7f, 0x80, +0x82, 0x84, 0x84, 0x82, 0x7e, 0x7c, 0x7c, 0x7e, 0x80, 0x80, 0x7e, 0x7b, +0x79, 0x7a, 0x7d, 0x80, 0x82, 0x81, 0x7f, 0x7e, 0x7f, 0x82, 0x85, 0x86, +0x85, 0x82, 0x80, 0x80, 0x82, 0x84, 0x84, 0x82, 0x7f, 0x7c, 0x7c, 0x7d, +0x7f, 0x80, 0x7e, 0x7b, 0x7a, 0x7a, 0x7d, 0x80, 0x81, 0x81, 0x7f, 0x7e, +0x7f, 0x82, 0x85, 0x86, 0x85, 0x82, 0x80, 0x80, 0x82, 0x84, 0x84, 0x82, +0x7f, 0x7c, 0x7c, 0x7d, 0x7f, 0x80, 0x7f, 0x7c, 0x7a, 0x7a, 0x7d, 0x80, +0x82, 0x81, 0x7f, 0x7d, 0x7e, 0x81, 0x84, 0x86, 0x85, 0x82, 0x80, 0x80, +0x81, 0x84, 0x84, 0x83, 0x80, 0x7d, 0x7c, 0x7d, 0x7f, 0x80, 0x7e, 0x7c, +0x7a, 0x7a, 0x7c, 0x7f, 0x81, 0x81, 0x7f, 0x7e, 0x7e, 0x81, 0x84, 0x85, +0x85, 0x83, 0x80, 0x80, 0x81, 0x83, 0x84, 0x83, 0x80, 0x7d, 0x7c, 0x7d, +0x7f, 0x80, 0x7e, 0x7c, 0x7a, 0x7a, 0x7c, 0x7f, 0x81, 0x81, 0x7f, 0x7e, +0x7e, 0x80, 0x84, 0x86, 0x85, 0x83, 0x81, 0x80, 0x82, 0x84, 0x84, 0x83, +0x80, 0x7e, 0x7c, 0x7d, 0x7f, 0x80, 0x7f, 0x7c, 0x7a, 0x7a, 0x7b, 0x7e, +0x80, 0x81, 0x7f, 0x7e, 0x7e, 0x80, 0x83, 0x85, 0x85, 0x84, 0x82, 0x81, +0x82, 0x83, 0x84, 0x83, 0x81, 0x7e, 0x7d, 0x7d, 0x7f, 0x7f, 0x7f, 0x7d, +0x7a, 0x7a, 0x7b, 0x7d, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x80, 0x83, 0x85, +0x85, 0x84, 0x82, 0x81, 0x82, 0x83, 0x84, 0x83, 0x81, 0x7f, 0x7d, 0x7d, +0x7f, 0x80, 0x7f, 0x7d, 0x7a, 0x79, 0x7b, 0x7d, 0x7f, 0x80, 0x7f, 0x7d, +0x7d, 0x7f, 0x82, 0x85, 0x85, 0x84, 0x82, 0x81, 0x82, 0x83, 0x85, 0x84, +0x82, 0x7f, 0x7d, 0x7d, 0x7f, 0x80, 0x7f, 0x7d, 0x7b, 0x79, 0x7a, 0x7d, +0x7f, 0x80, 0x7f, 0x7d, 0x7d, 0x7f, 0x82, 0x84, 0x85, 0x84, 0x82, 0x81, +0x81, 0x83, 0x85, 0x85, 0x83, 0x80, 0x7e, 0x7e, 0x7f, 0x80, 0x7f, 0x7d, +0x7b, 0x79, 0x7a, 0x7c, 0x7f, 0x7f, 0x7f, 0x7d, 0x7d, 0x7f, 0x81, 0x84, +0x84, 0x83, 0x82, 0x81, 0x82, 0x83, 0x85, 0x84, 0x83, 0x80, 0x7e, 0x7e, +0x7f, 0x80, 0x7f, 0x7d, 0x7b, 0x7a, 0x7a, 0x7c, 0x7e, 0x7f, 0x7e, 0x7d, +0x7d, 0x7e, 0x81, 0x83, 0x84, 0x84, 0x82, 0x81, 0x82, 0x83, 0x85, 0x85, +0x83, 0x80, 0x7e, 0x7e, 0x7f, 0x80, 0x7f, 0x7d, 0x7b, 0x7a, 0x7a, 0x7c, +0x7e, 0x7f, 0x7f, 0x7d, 0x7d, 0x7e, 0x81, 0x83, 0x84, 0x84, 0x82, 0x81, +0x81, 0x83, 0x84, 0x84, 0x83, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x7f, +0x7d, 0x7c, 0x7c, 0x7d, 0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x80, 0x82, +0x83, 0x83, 0x82, 0x80, 0x80, 0x81, 0x82, 0x83, 0x82, 0x80, 0x7e, 0x7e, +0x7e, 0x80, 0x80, 0x7f, 0x7d, 0x7c, 0x7c, 0x7d, 0x7f, 0x80, 0x80, 0x7f, +0x7e, 0x7e, 0x80, 0x82, 0x83, 0x83, 0x82, 0x81, 0x80, 0x81, 0x82, 0x83, +0x82, 0x80, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x7f, 0x7d, 0x7c, 0x7c, 0x7d, +0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x82, 0x83, 0x83, 0x82, 0x81, +0x80, 0x81, 0x82, 0x83, 0x82, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x7f, +0x7e, 0x7c, 0x7c, 0x7d, 0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x80, 0x82, +0x83, 0x83, 0x82, 0x81, 0x80, 0x81, 0x82, 0x83, 0x82, 0x80, 0x7f, 0x7f, +0x7f, 0x80, 0x7f, 0x7f, 0x7d, 0x7c, 0x7c, 0x7c, 0x7e, 0x80, 0x80, 0x80, +0x7f, 0x7e, 0x7f, 0x81, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x82, 0x83, +0x83, 0x82, 0x80, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x7e, 0x7d, 0x7c, 0x7c, +0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x81, 0x82, 0x83, 0x83, 0x82, +0x81, 0x81, 0x82, 0x83, 0x83, 0x82, 0x80, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +0x7e, 0x7d, 0x7c, 0x7c, 0x7d, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x81, +0x83, 0x84, 0x83, 0x82, 0x81, 0x81, 0x82, 0x83, 0x83, 0x82, 0x80, 0x7f, +0x7e, 0x7f, 0x80, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, 0x7d, 0x7f, 0x7f, 0x7f, +0x7e, 0x7e, 0x7f, 0x80, 0x82, 0x83, 0x83, 0x82, 0x81, 0x81, 0x82, 0x83, +0x83, 0x82, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, +0x7d, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x82, 0x83, 0x83, 0x82, +0x81, 0x81, 0x82, 0x83, 0x83, 0x82, 0x81, 0x7f, 0x7f, 0x7f, 0x80, 0x80, +0x7f, 0x7d, 0x7c, 0x7c, 0x7d, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x80, +0x82, 0x83, 0x83, 0x82, 0x81, 0x81, 0x82, 0x83, 0x83, 0x82, 0x81, 0x7f, +0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x7d, 0x7c, 0x7b, 0x7d, 0x7e, 0x80, 0x80, +0x7f, 0x7e, 0x7f, 0x80, 0x82, 0x83, 0x83, 0x82, 0x81, 0x81, 0x82, 0x83, +0x83, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7c, 0x7b, 0x7c, +0x7d, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x82, 0x83, 0x83, 0x82, +0x81, 0x81, 0x82, 0x83, 0x83, 0x82, 0x81, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7e, 0x7d, 0x7c, 0x7c, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, +0x82, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x81, 0x80, +0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7d, 0x7b, 0x7b, 0x7c, 0x7e, 0x7f, 0x7f, +0x7f, 0x7e, 0x7e, 0x80, 0x81, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x83, +0x83, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, +0x7c, 0x7d, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x81, 0x83, 0x83, 0x83, +0x83, 0x82, 0x82, 0x83, 0x83, 0x82, 0x82, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, +0x7e, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, +0x81, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x83, 0x83, 0x83, 0x82, 0x81, +0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7f, +0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x82, 0x82, 0x83, 0x82, 0x82, 0x81, 0x82, +0x82, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, +0x7d, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x82, 0x82, +0x82, 0x81, 0x81, 0x81, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, +0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, +0x81, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, +0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, +0x80, 0x80, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, +0x81, 0x81, 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7d, +0x7d, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, +0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, +0x7e, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, +0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, +0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, +0x80, 0x80, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, +0x81, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, +0x7d, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, +0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, +0x7e, 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x81, +0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, 0x80, +0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, +0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x82, 0x82, +0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, +0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, +0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7e, +0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x81, +0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, +0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, +0x7e, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, +0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, +0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, +0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, +0x7e, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x80, +0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, +0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, +0x7e, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, +0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, +0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, +0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, +0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, +0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x81, 0x81, 0x80, 0x80, 0x7f, +0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, +0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, +0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, +0x81, 0x81, 0x82, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, +0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x81, 0x81, 0x80, 0x80, +0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, +0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, +0x81, 0x81, 0x81, 0x82, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, +0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, +0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x81, 0x81, 0x80, 0x80, 0x80, +0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, +0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x81, +0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, +0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, +0x81, 0x81, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, +0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, +0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x81, 0x81, 0x80, +0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, +0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, +0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81, +0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +0x7f, 0x80, 0x80, 0x81, 0x81, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, +0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, +0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, +0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, +0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, +0x81, 0x81, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, +0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x82, 0x81, 0x81, 0x81, 0x82, 0x82, +0x82, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, +0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, +0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, +0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, +0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, +0x81, 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, +0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, +0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, +0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, +0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, +0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, +0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, +0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, +0x7f, 0x7f, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, +0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x81, 0x80, +0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, +0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, +0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, +0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x81, +0x80, 0x81, 0x81, 0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, +0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, 0x81, 0x80, +0x80, 0x80, 0x81, 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x82, +0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x7f, 0x7e, 0x7e, +0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x80, +0x80, 0x80, 0x81, 0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x7f, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, +0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, 0x81, 0x81, +0x80, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7d, 0x7e, 0x7f, 0x7f, +0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x80, 0x81, 0x82, +0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x7e, 0x7e, +0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, +0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x81, +0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, +0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, 0x81, +0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, +0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x81, +0x81, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x7f, 0x7e, +0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x80, +0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x81, +0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, +0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, +0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x81, +0x81, 0x81, 0x81, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, +0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x80, +0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, +0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, +0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, +0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, +0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x82, 0x81, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, +0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, +0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, +0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, +0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, +0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x80, +0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, +0x81, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, +0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, +0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x80, 0x80, +0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x81, 0x82, 0x81, 0x81, +0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, +0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, +0x81, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7e, +0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, +0x81, 0x80, 0x80, 0x80, 0x81, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x80, +0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x82, 0x81, 0x81, +0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, +0x81, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7e, +0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, +0x81, 0x80, 0x80, 0x81, 0x81, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x80, 0x80, +0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x82, 0x81, 0x81, +0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, +0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, +0x81, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7e, +0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x81, +0x81, 0x80, 0x80, 0x80, 0x81, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x80, +0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x81, +0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, +0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, +0x81, 0x82, 0x82, 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7e, +0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x81, +0x81, 0x80, 0x80, 0x80, 0x81, 0x82, 0x82, 0x81, 0x80, 0x80, 0x7f, 0x80, +0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x81, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, +0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, +0x81, 0x81, 0x82, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, +0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, +0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, +0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, +0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, +0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, +0x81, 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, +0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, +0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, +0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, +0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, +0x81, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, +0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, +0x81, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, +0x80, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x80, +0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, +0x81, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, +0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +0x80, 0x80, 0x80, 0x80, 0x80, 0x80, }; diff --git a/os/default/alAudio.c b/os/default/alAudio.c new file mode 100644 index 0000000..701ca9b --- /dev/null +++ b/os/default/alAudio.c @@ -0,0 +1,34 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alAudio.c + * + * alAudio.c,v 1.3 2003/02/27 17:20:08 jba Exp + * + */ + +#include "alh.h" + +/* Audio device not implemented */ + +/****************************************************** + alBeep +******************************************************/ +int alBeep(Display *displayBB) +{ + XBell(displayBB,0); + return 0; +} + + diff --git a/os/default/alAudio.h b/os/default/alAudio.h new file mode 100644 index 0000000..9d49b62 --- /dev/null +++ b/os/default/alAudio.h @@ -0,0 +1,20 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alAudio.h */ + +/* do not #define AUDIO_BEEP */ + +/*extern void alhAudioSetupCallback( Widget widget, XtPointer calldata, XtPointer cbs);*/ + diff --git a/os/solaris/alAudio.c b/os/solaris/alAudio.c new file mode 100644 index 0000000..6114c34 --- /dev/null +++ b/os/solaris/alAudio.c @@ -0,0 +1,918 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alAudio.c + * + alAudio.c,v 1.3 2002/08/02 15:37:48 jba Exp +*/ + +/************************DESCRIPTION*********************************** + Routines for audio output +**********************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/audioio.h> +#include <signal.h> +#include <stropts.h> + +#include <Xm/Xm.h> +#include <Xm/AtomMgr.h> +#include <Xm/Form.h> +#include <Xm/Frame.h> +#include <Xm/LabelG.h> +#include <Xm/PanedW.h> +#include <Xm/Protocols.h> +#include <Xm/PushB.h> +#include <Xm/TextF.h> +#include <Xm/ToggleB.h> +#include <Xm/ToggleBG.h> +#include <Xm/Scale.h> + +#include "alAudio.h" +#include "ax.h" +#include "beep.h" + +/* Pre solaris 8 definition */ +#ifndef AUDIO_NONE +#define AUDIO_NONE 0x00 /* all ports off */ +#endif + +#ifndef AUDIO_CHANNELS_STEREO +#define AUDIO_CHANNELS_STEREO (2) +#endif + +#ifndef AUDIO_MID_GAIN +#define AUDIO_MID_GAIN (AUDIO_MAX_GAIN / 2) +#endif + +#ifndef AUDIO_PRECISION_8 +#define AUDIO_PRECISION_8 (8) +#endif + +#ifndef AUDIO_CHANNELS_MONO +#define AUDIO_CHANNELS_MONO (1) +#endif +/* End of pre solaris 8 definition */ + +#define AUDIO_SOURCE_HI 0 +#define AUDIO_SOURCE_LO 1 +#define AUDIO_SOURCE_FILE 2 + +#define AU_PATTERN "*.au" + +extern Pixel bg_pixel[ALH_ALARM_NSEV]; + +static struct audioinfo { + char* filename; + unsigned char* pdata; + unsigned long dataSize; + unsigned long headerSize; + unsigned long audioSize; + int precision; /* bit-width of each sample 8,16,... */ + int encoding; /* data encoding method 0=none, 1=ULAW, 2=ALAW, 3=PCM */ + short sampleRate; /* samples per second */ + short channels; /* number of channels 1=mono 2=stereo */ + short littleEndian; /* not used yet */ + long samples; +}; + + +static struct beepsetup { + Widget audioSetupDialog; + Widget audioSourceFrameWidget; + short port; /* user selected I/O port */ + short volume; /* user selected gain level: 0 - 255 */ + short balance; /* user selected stereo channel balance - not implemented yet*/ + short audioSource; + struct audioinfo* paudioInfo; + struct audioinfo* paudioInfoFile; + struct audioinfo* paudioInfoInternalHi; + struct audioinfo* paudioInfoInternalLo; +} audioSetup={NULL,NULL,AUDIO_NONE,AUDIO_MID_GAIN,50,0,NULL,NULL,NULL} ; + +/* forward declarations */ +static void initAudioSetup(); +static unsigned char* readAudioData(char *filename,unsigned long *plength); +static struct audioinfo *createAudioInfo(char *filename,unsigned char *pdata,unsigned long length); +static int audioSetupNewFilename(Widget textfield, char *filename); +static int auAudioSettings(struct audioinfo *paudioInfo); +static void audioSetupCreateDialog(Widget menuButton); +static void audioSetupDismissCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupOutputChangeCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupVolumeChangeCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupAudioSourceChangeCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupTestBeepCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupFilenameChangeCallback(Widget widget,XtPointer clientdata,XtPointer cbs); +static void audioSetupFilenameBrowseCallback( Widget widget,XtPointer clientdata, XtPointer cbs); + + +/****************************************************** + alhAudioSetupCallback +******************************************************/ +void alhAudioSetupCallback( Widget menuButton, XtPointer clientdata, +XtPointer cbs) +{ + /* dismiss the dialog */ + if (audioSetup.audioSetupDialog && + XtIsManaged(audioSetup.audioSetupDialog)) { + audioSetupDismissCallback(audioSetup.audioSetupDialog, + (XtPointer)menuButton, NULL); + if (menuButton) XtVaSetValues(menuButton, XmNset, FALSE, NULL); + return; + } + + /* create audioSetupWindow and Dialog Widgets if necessary */ + if (!audioSetup.audioSetupDialog) audioSetupCreateDialog(menuButton); + + /* show Dialog */ + if (!audioSetup.audioSetupDialog) return; + if (!XtIsManaged(audioSetup.audioSetupDialog)){ + XtManageChild(audioSetup.audioSetupDialog); + } + + XMapWindow(XtDisplay(audioSetup.audioSetupDialog), + XtWindow(XtParent(audioSetup.audioSetupDialog))); + + if (menuButton) XtVaSetValues(menuButton, XmNset, TRUE, NULL); +} + +/****************************************************** + alAudioBeep +******************************************************/ +static int alAudioBeep() +{ + static struct audio_info sound_info; + audio_device_t dev_id; + int i; + int err; + static int fd = -1; + struct audioinfo *paudioInfo; + + if ( fd == -1 ) { + AUDIO_INITINFO(&sound_info); + fd = open("/dev/audio", O_WRONLY||O_NONBLOCK); + if ( fd == -1 ) { + errMsg("Error on open /dev/audio\n"); + return(-1); + } + } else { + ioctl (fd, I_SETSIG, 0); + ioctl (fd, I_FLUSH, FLUSHW); + } + + if ( ioctl(fd, AUDIO_GETINFO, &sound_info) == -1 ) { + errMsg("Error on ioctl get sound_info: %s\n",strerror(errno)); + close( fd ); + fd = -1; + return(-1); + } + + if (!audioSetup.paudioInfo) initAudioSetup(); + + paudioInfo = audioSetup.paudioInfo; + sound_info.play.sample_rate = paudioInfo->sampleRate; /* samples per second */ + sound_info.play.channels = paudioInfo->channels; /* number of interleaved channels */ + sound_info.play.precision = paudioInfo->precision; /* bit-width of each sample */ + sound_info.play.encoding = paudioInfo->encoding; /* data encoding method */ + + sound_info.play.port = audioSetup.port; /* user selected I/O port */ + sound_info.play.gain = audioSetup.volume; /* user selected gain level: 0 - 255 */ + /*uchar_t balance;*/ /* user selected stereo channel balance */ + + if ( err=ioctl(fd, AUDIO_SETINFO, &sound_info) == -1 ) { + errMsg("Error on ioctl set sound_info: %s \n",strerror(errno)); + close( fd ); + fd = -1; + return(-1); + } + + if ( paudioInfo->pdata==0 ){ + if (audioSetup.paudioInfo==audioSetup.paudioInfoFile){ + errMsg("No audio file specified\n"); + } else { + errMsg("No audio data\n"); + } + close( fd ); + fd = -1; + return(-1); + } + + if ( err=fcntl(fd, F_SETFL,O_NONBLOCK) == -1 ) { + errMsg("Error on fcntl set O_NONBLOCK: %s \n",strerror(errno)); + close( fd ); + fd = -1; + return(-1); + } + + if ( write(fd,paudioInfo->pdata+paudioInfo->headerSize, + paudioInfo->audioSize)!=paudioInfo->audioSize ){ + errMsg("Error on audio write: %s\n",strerror(errno)); + close( fd ); + fd = -1; + return(-1); + } + +#if 0 + close( fd ); + fd = -1; +#endif + return 0; +} + +/****************************************************** + alBeep +******************************************************/ +void alBeep(Display *displayBB) +{ + int percent; + int min=-100,max=100; + +/* Volume percent in call to XBell does not work */ +#if 0 + percent = max-(max-min)*((float)(AUDIO_MAX_GAIN-audioSetup.volume))/ + (AUDIO_MAX_GAIN-AUDIO_MIN_GAIN); +#endif + percent = 100; + + if (audioSetup.port==AUDIO_NONE){ + XBell(displayBB,percent); + } else { + if (alAudioBeep()){ + XBell(displayBB,percent); + } + } +} + +/****************************************************** + audioSetupCreateDialog +******************************************************/ +static void audioSetupCreateDialog(Widget menuButton) +{ + Widget audioSetupDialogShell; + Widget form,form1; + Widget filename; + Widget scale; + Widget button; + Widget toggleButton; + Widget frame, rowcol; + Widget label; + Pixel textBackground; + XmString string; + static ActionAreaItem audioSetup_items[] = { + { "Dismiss", audioSetupDismissCallback, NULL} }; + ALINK *area; + + if (!audioSetup.paudioInfo) initAudioSetup(); + + textBackground = bg_pixel[3]; + + XtVaGetValues(menuButton, XmNuserData, &area, NULL); + + if (audioSetup.audioSetupDialog){ + if (XtIsManaged(audioSetup.audioSetupDialog)) return; + else XtManageChild(audioSetup.audioSetupDialog); + } + + audioSetupDialogShell = XtVaCreatePopupShell("ALH Audio Setup", + transientShellWidgetClass, area->toplevel, NULL, 0); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(audioSetupDialogShell, + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(audioSetupDialogShell), + "WM_DELETE_WINDOW", False); + XmAddWMProtocolCallback(audioSetupDialogShell,WM_DELETE_WINDOW, + (XtCallbackProc)audioSetupDismissCallback, (XtPointer)menuButton); + } + + form = XtVaCreateWidget("audioSetupDialog", + xmFormWidgetClass, audioSetupDialogShell, + NULL); + audioSetup.audioSetupDialog = form; + + string = XmStringCreateSimple("Audio Beep Output Port"); + label = XtVaCreateManagedWidget("audioOutputLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_FORM, + XmNtopWidget, form, + NULL); + XmStringFree(string); + + frame = XtVaCreateWidget("frame", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, label, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + rowcol = XtVaCreateWidget("rowcol", + xmRowColumnWidgetClass, frame, + XmNspacing, 0, + XmNmarginWidth, 10, + XmNmarginHeight, 10, + XmNradioBehavior, TRUE, + XmNbackground, textBackground, + NULL); + + toggleButton = XtVaCreateManagedWidget("None (Use keyboard speaker)", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + NULL); + XmToggleButtonSetState(toggleButton, + ((audioSetup.port==AUDIO_NONE)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupOutputChangeCallback, (XtPointer)AUDIO_NONE); + + toggleButton = XtVaCreateManagedWidget("Internal speaker", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + NULL); + XmToggleButtonSetState(toggleButton, + ((audioSetup.port==AUDIO_SPEAKER)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupOutputChangeCallback, (XtPointer)AUDIO_SPEAKER); + + toggleButton = XtVaCreateManagedWidget("Headphone", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + NULL); + XmToggleButtonSetState(toggleButton, + ((audioSetup.port==AUDIO_HEADPHONE)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupOutputChangeCallback, (XtPointer)AUDIO_HEADPHONE); + + toggleButton = XtVaCreateManagedWidget("Line out", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + NULL); + XmToggleButtonSetState(toggleButton, + ((audioSetup.port==AUDIO_LINE_OUT)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupOutputChangeCallback, (XtPointer)AUDIO_LINE_OUT); + + XtManageChild(rowcol); + XtManageChild(frame); + + string = XmStringCreateSimple("Audio Source"); + label = XtVaCreateManagedWidget("audioAudioSourceLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, frame, + NULL); + XmStringFree(string); + + frame = XtVaCreateWidget("frame", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, label, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + audioSetup.audioSourceFrameWidget = frame; + if (audioSetup.port==AUDIO_NONE) XtSetSensitive(frame, FALSE); + else XtSetSensitive(frame, TRUE); + + rowcol = XtVaCreateWidget("rowcol", + xmRowColumnWidgetClass, frame, + XmNspacing, 0, + XmNmarginWidth, 10, + XmNmarginHeight, 10, + XmNradioBehavior, TRUE, + XmNbackground, textBackground, + NULL); + + toggleButton = XtVaCreateManagedWidget("alh internal Hi pitch beep", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + /*1XmNalignment,XmALIGNMENT_CENTER*/ + NULL); + XmToggleButtonSetState(toggleButton, + ((audioSetup.audioSource==AUDIO_SOURCE_HI)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupAudioSourceChangeCallback, (XtPointer)AUDIO_SOURCE_HI); + + toggleButton = XtVaCreateManagedWidget("alh internal Lo pitch beep", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + NULL); + XmToggleButtonSetState(toggleButton, + ((audioSetup.audioSource==AUDIO_SOURCE_LO)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupAudioSourceChangeCallback, (XtPointer)AUDIO_SOURCE_LO); + + toggleButton = XtVaCreateManagedWidget("Au/u-law (.au) file", + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNbackground, textBackground, + NULL); + XmToggleButtonSetState(toggleButton, + ((audioSetup.audioSource==AUDIO_SOURCE_FILE)?TRUE:FALSE),FALSE); + XtAddCallback(toggleButton, XmNvalueChangedCallback, + audioSetupAudioSourceChangeCallback, (XtPointer)AUDIO_SOURCE_FILE); + + XtManageChild(rowcol); + XtManageChild(frame); + + string = XmStringCreateSimple("Au/u-law (.au) filename"); + label = XtVaCreateManagedWidget("audioFilenamelabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, frame, + NULL); + XmStringFree(string); + + button = XtVaCreateManagedWidget("Browse", + xmPushButtonWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, frame, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, label, + XmNrightAttachment, XmATTACH_FORM, + XmNshadowThickness, 1, + NULL); + + filename = XtVaCreateManagedWidget("filename", + xmTextFieldWidgetClass, form, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, button, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtAddCallback(button, XmNactivateCallback, + audioSetupFilenameBrowseCallback, filename); + + XmTextFieldSetString(filename,audioSetup.paudioInfo->filename); + + XtAddCallback(filename, XmNactivateCallback, + audioSetupFilenameChangeCallback, NULL); + + string = XmStringCreateSimple("Audio Beep Volume"); + label = XtVaCreateManagedWidget("audioVolumelabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, filename, + NULL); + XmStringFree(string); + + frame = XtVaCreateWidget("frame", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, label, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + scale = XtVaCreateManagedWidget("VolumeScale", + xmScaleWidgetClass, frame, + XmNmaximum, AUDIO_MAX_GAIN, + XmNminimum, AUDIO_MIN_GAIN, + XmNvalue, audioSetup.volume, + XmNshowValue, True, + XmNorientation, XmHORIZONTAL, + XmNbackground, textBackground, + NULL); + XtAddCallback(scale, XmNvalueChangedCallback, + audioSetupVolumeChangeCallback, NULL); + + XtManageChild(frame); + + string = XmStringCreateSimple("Test Beep"); + label = XtVaCreateManagedWidget("audioTestlabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, frame, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + button = XtVaCreateManagedWidget("Beep", + xmPushButtonWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, label, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNshadowThickness, 2, + NULL); + XtAddCallback(button, XmNactivateCallback, + audioSetupTestBeepCallback, NULL); + + /* Set the client data "Dismiss" button's callbacks. */ + audioSetup_items[0].data = (XtPointer)menuButton; + + form1 = createActionButtons(form, audioSetup_items, + XtNumber(audioSetup_items)); + if (form1) XtVaSetValues(form1, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, button, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtManageChild(form); + XtRealizeWidget(audioSetupDialogShell); +} + +/****************************************************** + audioSetupSetupVolumeChangeCallback +******************************************************/ +static void audioSetupVolumeChangeCallback(Widget widget, XtPointer clientdata, +XtPointer cbs) +{ + audioSetup.volume = ((XmScaleCallbackStruct *)cbs)->value; +} + +/****************************************************** + audioSetupDismissCallback +******************************************************/ +static void audioSetupDismissCallback(Widget widget, XtPointer clientdata, +XtPointer cbs) +{ + Widget menuButton=(Widget)clientdata; + Widget dialog; + + dialog=audioSetup.audioSetupDialog; + XtUnmanageChild(dialog); + XUnmapWindow(XtDisplay(dialog), XtWindow(XtParent(dialog))); + if (menuButton) XtVaSetValues(menuButton, XmNset, FALSE, NULL); +} + +/****************************************************** + audioSetupTestBeepCallback +******************************************************/ +static void audioSetupTestBeepCallback( Widget widget, XtPointer clientdata, +XtPointer cbs) +{ + alBeep(XtDisplay(widget)); +} + +/****************************************************** + audioSetupAudioSourceChangeCallback +******************************************************/ +static void audioSetupAudioSourceChangeCallback( Widget widget, + XtPointer clientdata, XtPointer cbs) +{ + XmToggleButtonCallbackStruct *state = + (XmToggleButtonCallbackStruct *) cbs; + + if (state->set) { + audioSetup.audioSource = (int)clientdata; + + switch (audioSetup.audioSource) { + case AUDIO_SOURCE_HI: + audioSetup.paudioInfo = audioSetup.paudioInfoInternalHi; + break; + case AUDIO_SOURCE_LO: + audioSetup.paudioInfo = audioSetup.paudioInfoInternalLo; + break; + case AUDIO_SOURCE_FILE: + audioSetup.paudioInfo = audioSetup.paudioInfoFile; + break; + } + } +} + +/****************************************************** + audioSetupOutputChangeCallback +******************************************************/ +static void audioSetupOutputChangeCallback( Widget widget, + XtPointer clientdata, XtPointer cbs) +{ + XmToggleButtonCallbackStruct *state = + (XmToggleButtonCallbackStruct *) cbs; + + if (state->set) { + audioSetup.port = (int)clientdata; + + if (audioSetup.port==AUDIO_NONE){ + XtSetSensitive(audioSetup.audioSourceFrameWidget, FALSE); + } else { + XtSetSensitive(audioSetup.audioSourceFrameWidget, TRUE); + } + } +} + +/****************************************************** + audioSetupFileSelectCallback +******************************************************/ +void audioSetupFileSelectCallback(Widget widget, XtPointer clientdata, +XtPointer *cbs) +{ + char *string; + + /* get the filename string */ + XmStringGetLtoR(((XmFileSelectionBoxCallbackStruct *)cbs)->value, + XmSTRING_DEFAULT_CHARSET, &string); + + if (strlen(string) && + !audioSetupNewFilename((Widget)clientdata,string)) + XtUnmanageChild(widget); + XtFree(string); +} + +/****************************************************** + audioSetupFilenameBrowseCallback +******************************************************/ +static void audioSetupFilenameBrowseCallback( Widget widget, + XtPointer clientdata, XtPointer cbs) +{ + createFileDialog(widget, + (void *)audioSetupFileSelectCallback,(XtPointer)clientdata, + (void *)XtUnmanageChild,(XtPointer)0, + (XtPointer)0,"Au/u-law (.au) file",AU_PATTERN,0); +} + +/****************************************************** + audioSetupFilenameChangeCallback +******************************************************/ +static void audioSetupFilenameChangeCallback( Widget widget, + XtPointer clientdata, XtPointer cbs) +{ + char * string; + + string = XmTextFieldGetString(widget); + audioSetupNewFilename(widget,string); + XtFree(string); +} + +/****************************************************** + audioSetupNewFilename +******************************************************/ +static int audioSetupNewFilename(Widget widget, char *string) +{ + char* filename; + int filenameSize; + char* plast; + unsigned char* pdata; + struct audioinfo* poldAudioInfoFile; + struct audioinfo* paudioInfo; + unsigned long length; + + filename = string; + /* remove leading white space */ + while (isspace(*filename)) { + filename++; + continue; + } + + /* remove trailing white space */ + plast=filename + strlen(filename)-1; + while (isspace(*plast)) { + *plast=0; + plast--; + } + filenameSize = strlen(filename); + if (!filenameSize) return 0; + if (filename[filenameSize-1]=='/'||filename[filenameSize-1]=='\\') return 0; + + XmTextFieldSetString(widget,filename); + + pdata = readAudioData(filename,&length); + if (!pdata){ + return -1; + } + + paudioInfo = createAudioInfo(filename,pdata,length); + if (!paudioInfo){ + return -1; + } + + poldAudioInfoFile = audioSetup.paudioInfoFile; + audioSetup.paudioInfoFile = paudioInfo; + if (audioSetup.audioSource==AUDIO_SOURCE_FILE) { + audioSetup.paudioInfo = paudioInfo; + } + + if (poldAudioInfoFile){ + if (poldAudioInfoFile->filename) free(poldAudioInfoFile->filename); + if (poldAudioInfoFile->pdata) free(poldAudioInfoFile->pdata); + free(poldAudioInfoFile); + } + + return 0; +} + +/****************************************************** + initAudioSetup +******************************************************/ +static void initAudioSetup() +{ + if ( audioSetup.paudioInfo==0 ){ + if ( audioSetup.paudioInfoInternalHi==0 ) { + audioSetup.paudioInfoInternalHi = createAudioInfo("internalHiBeep", + beepHi,beepHiLength); + audioSetup.paudioInfoInternalLo = createAudioInfo("internalLoBeep", + beepLo,beepLoLength); + } + audioSetup.paudioInfo = audioSetup.paudioInfoInternalHi; + } +} + +/****************************************************** + readAudioData +******************************************************/ +static unsigned char * readAudioData(char *filename,unsigned long *plength) +{ + unsigned long dataSize; + unsigned long length; + FILE* fp; + unsigned char* pfileData; + + fp = fopen(filename,"rb"); + if(!fp) { + errMsg("Error: %s Could not open audio file %s.\n", + strerror(errno),filename); + return 0; + } + /* Get size of audio file */ + fseek(fp,0L,SEEK_END); + dataSize=ftell(fp); + if(dataSize==-1) { + errMsg("Error determining size of audio file %s.\n",filename); + fclose(fp); + return 0; + } + fseek(fp,0L,SEEK_SET); + pfileData = calloc(dataSize,sizeof(unsigned char)); + if(!pfileData) { + errMsg("Error allocating memory for audio file %s.\n",filename); + fclose(fp); + return 0; + } + length = fread(pfileData,sizeof(unsigned char),dataSize,fp); + if(feof(fp)) { + errMsg("Error reading audio file %s. End of file encountered.\n",filename); + fclose(fp); + free(pfileData); + return 0; + } + if(length != dataSize) { + errMsg("Error reading audio file %s.\n",filename); + fclose(fp); + free(pfileData); + return 0; + } + fclose(fp); + *plength = length; + return pfileData; +} + +/****************************************************** + createAudioInfo +******************************************************/ +static struct audioinfo *createAudioInfo(char *filename,unsigned char *pdata, +unsigned long length) +{ + struct audioinfo *paudioInfo; + unsigned char hdr[16]; + + paudioInfo = (struct audioinfo *)calloc(1,sizeof(struct audioinfo)); + + paudioInfo->pdata = pdata; + paudioInfo->dataSize = length; + + memcpy(hdr,paudioInfo->pdata,16); + if (!memcmp(paudioInfo->pdata,".snd",4)){ + if( auAudioSettings(paudioInfo)){ + errMsg("Error in au audio file %s.\n",filename); + free(paudioInfo); + return 0; + } + } else { + if (!memcmp(paudioInfo->pdata,"RIFF",4)){ +/* wave files not implemented yet */ + errMsg("Error: alh cannot read wave audio file %s.\n",filename); + free(paudioInfo); + return 0; +#if 0 + if( waveAudioSettings(paudioInfo)){ + errMsg("Error in wave audio file %s.\n",filename); + free(paudioInfo); + return 0; + } +#endif + } else { + /* Assume headerless ULAW file */ + paudioInfo->headerSize = 0; + paudioInfo->audioSize = length; + paudioInfo->precision = AUDIO_PRECISION_8; + paudioInfo->encoding = AUDIO_ENCODING_ULAW; + paudioInfo->sampleRate = 8000; + paudioInfo->channels = AUDIO_CHANNELS_MONO; + paudioInfo->littleEndian = 0; + paudioInfo->samples = -1; + } + } + + paudioInfo->filename = (char *)calloc(1,strlen(filename)+1); + strcpy(paudioInfo->filename,filename); + + return paudioInfo; +} + +/****************************************************** + auAudioSettings +******************************************************/ +static int auAudioSettings(struct audioinfo *paudioInfo) +{ + struct header{ + long magic; + long headerSize; + long audioSize; + long encoding; + long sampleRate; + long channels; + }; + struct header* phdr; + + phdr = (struct header*)paudioInfo->pdata; + +#ifdef DEBUG + printf("dataSize=%ld\n",paudioInfo->dataSize); + printf("headerSize=%ld\n", phdr->headerSize); + printf("audioSize=%ld\n", phdr->audioSize); + printf("encoding=%ld\n", phdr->encoding); + printf("sampleRate=%ld\n", phdr->sampleRate); + printf("channels=%ld\n", phdr->channels); +#endif + + paudioInfo->headerSize = phdr->headerSize; + paudioInfo->audioSize = phdr->audioSize; + paudioInfo->encoding = phdr->encoding; + paudioInfo->sampleRate = phdr->sampleRate; + paudioInfo->channels = phdr->channels; + paudioInfo->littleEndian = 0; + + switch (phdr->encoding) + { + case 1: + paudioInfo->precision = 8; + break; + case 2: + paudioInfo->precision = 8; + break; + case 3: + paudioInfo->precision = 16; + break; + case 4: + paudioInfo->encoding = AUDIO_ENCODING_LINEAR; + paudioInfo->precision = 24; + break; + case 5: + paudioInfo->encoding = AUDIO_ENCODING_LINEAR; + paudioInfo->precision = 32; + break; + default: + return -1; + } + paudioInfo->samples = phdr->audioSize/(phdr->channels*(paudioInfo->precision/8)); + +#ifdef DEBUG + printf("precision=%ld\n", paudioInfo->precision); + printf("samples=%ld\n\n", paudioInfo->samples); +#endif + + return 0; +} + +/****************************************************** + waveAudioSettings +******************************************************/ +static int waveAudioSettings(struct audioinfo *paudioInfo) +{ + /* not implemented yet */ + return 0; +} + diff --git a/os/solaris/alAudio.h b/os/solaris/alAudio.h new file mode 100644 index 0000000..8cc692a --- /dev/null +++ b/os/solaris/alAudio.h @@ -0,0 +1,22 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* alAudio.h */ + +#include "axArea.h" + +#define AUDIO_BEEP 1 + +extern void alhAudioSetupCallback( Widget widget, XtPointer calldata, XtPointer cbs); + diff --git a/os/solaris/beep.h b/os/solaris/beep.h new file mode 100644 index 0000000..d9f1709 --- /dev/null +++ b/os/solaris/beep.h @@ -0,0 +1,1786 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* from DingJbaLo3ulaw.au and DingJbaHi3ulaw.au */ +int beepHiLength = 10390 ; +unsigned char beepHi[] = { +0x2e, 0x73, 0x6e, 0x64, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x28, 0x7a, +0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1f, 0x40, 0x0, 0x0, 0x0, 0x2, +0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0xff, 0xff, 0xff, 0xfe, 0x7f, +0x7e, 0x7d, 0x7c, 0x7d, 0x7b, 0x7c, 0x7c, 0x7e, 0x7e, 0xfe, 0xfe, 0xfb, +0xfc, 0xf9, 0xfb, 0xf8, 0xfb, 0xf9, 0xfb, 0xfa, 0xfd, 0xfc, 0x7e, 0x7f, +0x7d, 0x7e, 0x7c, 0x7c, 0x7b, 0x7b, 0x7c, 0x7d, 0x7f, 0x7f, 0xfd, 0xfd, +0xfb, 0xfd, 0xfa, 0xfd, 0xfb, 0xfe, 0xfc, 0xfe, 0xfe, 0xfe, 0x7e, 0x7e, +0x7d, 0x7e, 0x7d, 0x7e, 0x7d, 0x7e, 0xff, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, +0xfe, 0xfe, 0x7e, 0xfe, 0x7c, 0x7e, 0x7b, 0x7d, 0x7a, 0x7b, 0x78, 0x79, +0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7b, 0x7b, 0x7e, 0x7d, 0xff, 0x7f, +0xfd, 0xfe, 0xfc, 0xfe, 0xfc, 0xfe, 0xfc, 0xfd, 0xfb, 0xfd, 0xfb, 0xff, +0xf9, 0xff, 0xf7, 0xfd, 0xf7, 0xfc, 0xf6, 0xfa, 0xfb, 0xfe, 0x7d, 0x79, +0xe3, 0xe3, 0x6a, 0x68, 0xdc, 0xdc, 0x55, 0x53, 0xd0, 0xce, 0xb3, 0xb2, +0x38, 0x37, 0x31, 0x30, 0xdc, 0xda, 0xc5, 0xc5, 0x3f, 0x3e, 0xb3, 0xb1, +0xcb, 0xcb, 0x59, 0x5c, 0xc9, 0xc8, 0x2f, 0x2e, 0x5a, 0x5b, 0x3a, 0x39, +0x3e, 0x3e, 0xb1, 0xb0, 0x6c, 0x6a, 0xaf, 0xae, 0xba, 0xba, 0x4e, 0x4e, +0xc8, 0xc8, 0x2e, 0x2d, 0x4c, 0x4b, 0x4d, 0x4a, 0x3e, 0x3d, 0x7d, 0x6c, +0x4e, 0x4d, 0xa5, 0xa3, 0xc4, 0xc4, 0x3a, 0x3a, 0xc7, 0xc6, 0x26, 0x24, +0x2f, 0x2e, 0x3c, 0x3a, 0x38, 0x38, 0xa8, 0xa6, 0xb4, 0xb1, 0x9f, 0x9e, +0x99, 0x97, 0xb2, 0xaf, 0xc0, 0xbd, 0x1f, 0x1e, 0x18, 0x16, 0x18, 0x15, +0x17, 0x15, 0x72, 0x62, 0xa9, 0xa8, 0x94, 0x91, 0x8f, 0x8d, 0x9e, 0x9c, +0xab, 0xa8, 0x20, 0x1e, 0x13, 0x10, 0x12, 0xf, 0x11, 0xf, 0x3a, 0x36, +0xaa, 0xa9, 0x94, 0x91, 0x8d, 0x8b, 0x98, 0x95, 0xa0, 0x9e, 0x29, 0x28, +0x11, 0xf, 0xf, 0xd, 0xe, 0xd, 0x2a, 0x26, 0xb2, 0xb0, 0x95, 0x93, +0x8b, 0x89, 0x92, 0x8f, 0x9c, 0x99, 0x36, 0x35, 0x14, 0x12, 0xf, 0xe, +0xd, 0xb, 0x1e, 0x1c, 0xd0, 0xd5, 0x99, 0x98, 0x8c, 0x8a, 0x90, 0x8e, +0x95, 0x92, 0xdd, 0xd4, 0x17, 0x15, 0x10, 0xe, 0xc, 0xa, 0x1a, 0x18, +0x4b, 0x42, 0x9f, 0x9d, 0x8c, 0x8b, 0x8f, 0x8d, 0x94, 0x90, 0xb9, 0xb5, +0x1a, 0x18, 0x11, 0xe, 0xb, 0x9, 0x14, 0x11, 0x34, 0x2e, 0xa3, 0xa0, +0x8d, 0x8b, 0x8d, 0x8b, 0x90, 0x8d, 0xa8, 0xa4, 0x1d, 0x1c, 0x11, 0xf, +0xb, 0x9, 0xf, 0xe, 0x27, 0x21, 0xb0, 0xaf, 0x8e, 0x8c, 0x8c, 0x8a, +0x8e, 0x8b, 0x9d, 0x9a, 0x26, 0x25, 0x14, 0x10, 0xb, 0xa, 0xd, 0xb, +0x1d, 0x19, 0xdb, 0xe1, 0x91, 0x8f, 0x8c, 0x8a, 0x8d, 0x8a, 0x96, 0x92, +0x3c, 0x3e, 0x18, 0x15, 0xc, 0xb, 0xc, 0xa, 0x17, 0x12, 0x32, 0x2d, +0x97, 0x94, 0x8d, 0x8b, 0x8d, 0x8a, 0x91, 0x8e, 0xcc, 0xc0, 0x1f, 0x1d, +0xe, 0xc, 0xc, 0xa, 0x15, 0x10, 0x25, 0x1f, 0x9e, 0x9c, 0x8f, 0x8d, +0x8e, 0x8b, 0x8e, 0x8c, 0xb3, 0xad, 0x29, 0x26, 0x11, 0xf, 0xc, 0xa, +0x15, 0x10, 0x1f, 0x1c, 0xa9, 0xa6, 0x92, 0x8f, 0x8f, 0x8c, 0x8f, 0x8c, +0xab, 0xa6, 0x30, 0x2e, 0x16, 0x12, 0xd, 0xa, 0x16, 0x11, 0x20, 0x1d, +0xad, 0xab, 0x94, 0x90, 0x90, 0x8d, 0x8f, 0x8c, 0xa9, 0xa4, 0x33, 0x31, +0x17, 0x14, 0xd, 0xa, 0x16, 0x11, 0x1f, 0x1c, 0xb1, 0xae, 0x93, 0x8f, +0x91, 0x8d, 0x8e, 0x8b, 0xa4, 0x9f, 0x36, 0x34, 0x19, 0x15, 0xc, 0xa, +0x12, 0xe, 0x1c, 0x18, 0xc4, 0xc3, 0x95, 0x90, 0x90, 0x8d, 0x8d, 0x8a, +0x9d, 0x99, 0x49, 0x4c, 0x1d, 0x1a, 0xd, 0xa, 0x11, 0xd, 0x19, 0x14, +0x4c, 0x45, 0x98, 0x94, 0x92, 0x8e, 0x8d, 0x8a, 0x9a, 0x95, 0xf7, 0xda, +0x22, 0x1e, 0xe, 0xb, 0x10, 0xd, 0x19, 0x14, 0x39, 0x34, 0x9b, 0x97, +0x93, 0x8f, 0x8e, 0x8a, 0x98, 0x93, 0xcf, 0xc4, 0x25, 0x21, 0xf, 0xc, +0xf, 0xc, 0x18, 0x12, 0x30, 0x2c, 0x9d, 0x9a, 0x94, 0x8f, 0x8e, 0x8a, +0x96, 0x90, 0xbe, 0xb6, 0x2a, 0x27, 0xf, 0xc, 0xf, 0xc, 0x17, 0x11, +0x28, 0x22, 0x9f, 0x9c, 0x96, 0x90, 0x8e, 0x8b, 0x93, 0x8e, 0xb7, 0xaf, +0x31, 0x2e, 0x12, 0xe, 0xe, 0xb, 0x16, 0x10, 0x21, 0x1d, 0xa6, 0xa1, +0x96, 0x91, 0x8f, 0x8c, 0x90, 0x8d, 0xad, 0xa7, 0x38, 0x35, 0x14, 0xf, +0xe, 0xa, 0x15, 0xf, 0x1e, 0x19, 0xad, 0xaa, 0x97, 0x92, 0x8f, 0x8c, +0x8f, 0x8c, 0xa6, 0x9f, 0x4a, 0x47, 0x17, 0x12, 0xe, 0xa, 0x13, 0xd, +0x1b, 0x16, 0xb8, 0xb6, 0x99, 0x94, 0x90, 0x8c, 0x8e, 0x8a, 0xa0, 0x9b, +0xe5, 0xd9, 0x1a, 0x15, 0xe, 0xa, 0x12, 0xd, 0x18, 0x12, 0xd5, 0xd9, +0x9b, 0x97, 0x91, 0x8d, 0x8d, 0x8a, 0x9c, 0x97, 0xbd, 0xb6, 0x1e, 0x1a, +0xe, 0xb, 0x11, 0xc, 0x15, 0xf, 0x49, 0x40, 0x9e, 0x9a, 0x94, 0x8e, +0x8d, 0x89, 0x9a, 0x94, 0xb5, 0xad, 0x25, 0x1f, 0xf, 0xb, 0x11, 0xc, +0x15, 0xf, 0x34, 0x2e, 0xa0, 0x9c, 0x95, 0x8f, 0x8d, 0x8a, 0x97, 0x91, +0xae, 0xa8, 0x2b, 0x27, 0x11, 0xc, 0x11, 0xc, 0x14, 0xe, 0x2b, 0x25, +0xa6, 0xa0, 0x97, 0x91, 0x8e, 0x8a, 0x95, 0x8f, 0xa9, 0xa1, 0x33, 0x2e, +0x13, 0xe, 0x11, 0xc, 0x12, 0xc, 0x25, 0x1e, 0xab, 0xa7, 0x9a, 0x94, +0x8e, 0x8a, 0x93, 0x8e, 0xa4, 0x9d, 0x45, 0x42, 0x14, 0xf, 0x11, 0xc, +0x11, 0xc, 0x1e, 0x19, 0xb3, 0xaf, 0x9c, 0x97, 0x8e, 0x8b, 0x91, 0x8d, +0xa1, 0x9b, 0xe2, 0xd7, 0x18, 0x11, 0x11, 0xc, 0x11, 0xc, 0x1b, 0x14, +0xbf, 0xbf, 0x9f, 0x9a, 0x8f, 0x8b, 0x90, 0x8c, 0x9e, 0x99, 0xc0, 0xba, +0x1b, 0x15, 0x12, 0xd, 0x12, 0xc, 0x19, 0x12, 0xde, 0xf7, 0xa3, 0x9d, +0x92, 0x8d, 0x90, 0x8b, 0x9d, 0x97, 0xb6, 0xae, 0x1e, 0x19, 0x14, 0xd, +0x12, 0xc, 0x17, 0xf, 0x4d, 0x41, 0xa7, 0xa1, 0x94, 0x8d, 0x8f, 0x8b, +0x9b, 0x94, 0xad, 0xa6, 0x22, 0x1d, 0x15, 0xe, 0x12, 0xc, 0x15, 0xe, +0x3c, 0x33, 0xac, 0xa7, 0x96, 0x8f, 0x8f, 0x8a, 0x9a, 0x92, 0xa7, 0x9f, +0x2a, 0x24, 0x16, 0xf, 0x13, 0xd, 0x13, 0xd, 0x2f, 0x29, 0xb2, 0xad, +0x99, 0x92, 0x8f, 0x8a, 0x99, 0x91, 0xa3, 0x9c, 0x34, 0x2f, 0x18, 0x11, +0x14, 0xe, 0x13, 0xc, 0x29, 0x21, 0xbc, 0xb8, 0x9c, 0x96, 0x90, 0x8b, +0x97, 0x8f, 0x9f, 0x9a, 0x43, 0x3e, 0x1a, 0x14, 0x15, 0xe, 0x12, 0xc, +0x23, 0x1c, 0xcd, 0xcb, 0x9f, 0x99, 0x91, 0x8b, 0x96, 0x8f, 0x9e, 0x97, +0xfb, 0xf1, 0x1c, 0x16, 0x17, 0xf, 0x11, 0xb, 0x1f, 0x19, 0x67, 0x57, +0xa4, 0x9d, 0x92, 0x8c, 0x96, 0x8e, 0x9c, 0x94, 0xbe, 0xb8, 0x1f, 0x19, +0x18, 0x10, 0x12, 0xb, 0x1c, 0x15, 0x47, 0x3e, 0xaa, 0xa3, 0x94, 0x8d, +0x95, 0x8d, 0x9b, 0x93, 0xb1, 0xab, 0x23, 0x1c, 0x1a, 0x12, 0x12, 0xb, +0x1a, 0x11, 0x3b, 0x33, 0xb1, 0xab, 0x96, 0x8e, 0x94, 0x8d, 0x9a, 0x91, +0xaa, 0xa2, 0x29, 0x21, 0x1b, 0x13, 0x13, 0xc, 0x18, 0xf, 0x30, 0x29, +0xba, 0xb2, 0x98, 0x8f, 0x94, 0x8d, 0x98, 0x8f, 0xa5, 0x9d, 0x2f, 0x2a, +0x1d, 0x16, 0x13, 0xc, 0x16, 0xe, 0x2b, 0x22, 0xcf, 0xcc, 0x9a, 0x92, +0x95, 0x8d, 0x98, 0x8f, 0x9f, 0x99, 0x39, 0x32, 0x1f, 0x19, 0x15, 0xd, +0x14, 0xd, 0x28, 0x1f, 0x5a, 0x4e, 0x9e, 0x97, 0x95, 0x8d, 0x98, 0x8f, +0x9d, 0x95, 0x4a, 0x47, 0x22, 0x1b, 0x17, 0xe, 0x13, 0xc, 0x23, 0x1b, +0x43, 0x3a, 0xa2, 0x9b, 0x96, 0x8e, 0x98, 0x8f, 0x9b, 0x93, 0xdc, 0xd0, +0x25, 0x1d, 0x19, 0x10, 0x13, 0xb, 0x1f, 0x18, 0x3a, 0x2f, 0xa8, 0x9f, +0x97, 0x8e, 0x98, 0x8f, 0x9a, 0x91, 0xbf, 0xb7, 0x29, 0x21, 0x1a, 0x11, +0x13, 0xb, 0x1d, 0x15, 0x31, 0x29, 0xad, 0xa6, 0x98, 0x8f, 0x98, 0x8f, +0x99, 0x8f, 0xb4, 0xac, 0x2e, 0x27, 0x1c, 0x14, 0x14, 0xc, 0x1c, 0x14, +0x2c, 0x22, 0xb7, 0xae, 0x9a, 0x91, 0x99, 0x8f, 0x98, 0x8e, 0xac, 0xa3, +0x35, 0x2d, 0x1f, 0x18, 0x14, 0xb, 0x1b, 0x12, 0x29, 0x1f, 0xc8, 0xc0, +0x9b, 0x92, 0x99, 0x8f, 0x98, 0x8e, 0xa7, 0x9d, 0x3b, 0x37, 0x23, 0x1b, +0x16, 0xc, 0x1a, 0x10, 0x27, 0x1e, 0x7c, 0x65, 0x9e, 0x96, 0x9a, 0x8f, +0x98, 0x8e, 0xa2, 0x99, 0x50, 0x47, 0x27, 0x1d, 0x17, 0xd, 0x19, 0xf, +0x23, 0x1b, 0x4a, 0x3f, 0xa1, 0x99, 0x9b, 0x90, 0x98, 0x8e, 0x9f, 0x97, +0xe9, 0xea, 0x2b, 0x22, 0x18, 0xe, 0x19, 0xe, 0x21, 0x19, 0x3a, 0x2e, +0xa6, 0x9c, 0x9c, 0x92, 0x98, 0x8e, 0x9d, 0x93, 0xca, 0xc4, 0x30, 0x27, +0x1a, 0xf, 0x18, 0xd, 0x1f, 0x17, 0x31, 0x29, 0xaa, 0x9f, 0x9d, 0x92, +0x99, 0x8e, 0x9c, 0x91, 0xbd, 0xb7, 0x39, 0x2b, 0x1d, 0x11, 0x18, 0xd, +0x1f, 0x15, 0x2b, 0x23, 0xb1, 0xa4, 0x9e, 0x92, 0x9a, 0x8e, 0x9a, 0x8f, +0xb3, 0xac, 0x40, 0x2f, 0x1f, 0x14, 0x18, 0xc, 0x1e, 0x13, 0x29, 0x1f, +0xbc, 0xac, 0xa0, 0x94, 0x9b, 0x8e, 0x9a, 0x8e, 0xad, 0xa4, 0x51, 0x3a, +0x22, 0x16, 0x19, 0xd, 0x1d, 0x12, 0x25, 0x1c, 0xc9, 0xb6, 0xa3, 0x96, +0x9c, 0x8f, 0x99, 0x8d, 0xaa, 0x9f, 0xf1, 0x4f, 0x26, 0x19, 0x19, 0xd, +0x1d, 0x11, 0x22, 0x19, 0xfe, 0xd1, 0xa6, 0x98, 0x9d, 0x90, 0x99, 0x8d, +0xa7, 0x9c, 0xd1, 0xe0, 0x2b, 0x1d, 0x1a, 0xd, 0x1d, 0x10, 0x21, 0x17, +0x49, 0x47, 0xa8, 0x9a, 0x9f, 0x92, 0x99, 0x8d, 0xa4, 0x99, 0xc7, 0xc7, +0x30, 0x21, 0x1c, 0xe, 0x1d, 0xf, 0x20, 0x16, 0x3c, 0x34, 0xad, 0x9d, +0xa0, 0x93, 0x9a, 0x8d, 0xa1, 0x96, 0xbd, 0xb8, 0x37, 0x27, 0x1d, 0xf, +0x1d, 0xf, 0x1f, 0x14, 0x34, 0x2b, 0xb1, 0xa1, 0xa3, 0x95, 0x9b, 0x8d, +0x9f, 0x94, 0xb7, 0xae, 0x40, 0x2e, 0x1f, 0x11, 0x1d, 0xf, 0x1f, 0x13, +0x2e, 0x24, 0xb8, 0xa7, 0xa6, 0x98, 0x9b, 0x8d, 0x9f, 0x92, 0xb3, 0xa9, +0x55, 0x3d, 0x20, 0x13, 0x1d, 0xf, 0x1f, 0x12, 0x2a, 0x1e, 0xbd, 0xad, +0xa9, 0x9a, 0x9c, 0x8e, 0x9e, 0x90, 0xaf, 0xa5, 0xec, 0x5e, 0x25, 0x17, +0x1e, 0xf, 0x1f, 0x12, 0x27, 0x1b, 0xcb, 0xba, 0xab, 0x9c, 0x9e, 0x8f, +0x9d, 0x8f, 0xac, 0x9f, 0xcf, 0xcf, 0x28, 0x1a, 0x1e, 0xf, 0x1f, 0x12, +0x26, 0x19, 0xea, 0xd3, 0xad, 0x9e, 0x9e, 0x91, 0x9d, 0x8e, 0xaa, 0x9d, +0xc1, 0xbb, 0x2c, 0x1d, 0x1f, 0x11, 0x1f, 0x11, 0x22, 0x16, 0x58, 0x53, +0xb2, 0xa2, 0xa0, 0x92, 0x9c, 0x8e, 0xa8, 0x9b, 0xba, 0xb0, 0x30, 0x21, +0x1f, 0x11, 0x1f, 0x11, 0x21, 0x15, 0x43, 0x3b, 0xb7, 0xa5, 0xa3, 0x95, +0x9c, 0x8e, 0xa6, 0x99, 0xb4, 0xab, 0x39, 0x28, 0x22, 0x12, 0x20, 0x11, +0x1f, 0x13, 0x3a, 0x2e, 0xbd, 0xaa, 0xa7, 0x97, 0x9c, 0x8e, 0xa5, 0x96, +0xb1, 0xa7, 0x45, 0x31, 0x24, 0x14, 0x21, 0x11, 0x1f, 0x12, 0x33, 0x26, +0xc4, 0xaf, 0xaa, 0x9a, 0x9d, 0x8e, 0xa3, 0x94, 0xae, 0xa2, 0x55, 0x40, +0x26, 0x17, 0x22, 0x12, 0x1f, 0x10, 0x2e, 0x1f, 0xd2, 0xbc, 0xad, 0x9c, +0x9e, 0x8e, 0xa2, 0x93, 0xac, 0x9e, 0xdf, 0x7c, 0x29, 0x19, 0x23, 0x12, +0x1f, 0xf, 0x2b, 0x1d, 0xfb, 0xcd, 0xb3, 0x9f, 0x9f, 0x8f, 0xa1, 0x91, +0xaa, 0x9c, 0xc4, 0xbf, 0x2c, 0x1b, 0x25, 0x14, 0x1f, 0x10, 0x27, 0x19, +0x55, 0x66, 0xbb, 0xa6, 0xa1, 0x91, 0xa0, 0x90, 0xa9, 0x9b, 0xba, 0xb0, +0x31, 0x1f, 0x27, 0x15, 0x1f, 0x10, 0x25, 0x16, 0x44, 0x3d, 0xc2, 0xab, +0xa4, 0x93, 0xa1, 0x90, 0xa7, 0x99, 0xb4, 0xaa, 0x37, 0x24, 0x29, 0x16, +0x20, 0x11, 0x23, 0x15, 0x3c, 0x32, 0xd0, 0xb3, 0xa7, 0x96, 0xa1, 0x90, +0xa7, 0x98, 0xaf, 0xa6, 0x3f, 0x2b, 0x2b, 0x18, 0x22, 0x12, 0x22, 0x14, +0x38, 0x2d, 0xee, 0xbd, 0xaa, 0x99, 0xa2, 0x91, 0xa7, 0x98, 0xad, 0xa1, +0x4b, 0x31, 0x2d, 0x1a, 0x24, 0x14, 0x21, 0x13, 0x34, 0x2a, 0x5c, 0xcc, +0xae, 0x9c, 0xa2, 0x91, 0xa7, 0x98, 0xab, 0x9e, 0x69, 0x3e, 0x2f, 0x1c, +0x27, 0x16, 0x20, 0x12, 0x2f, 0x25, 0x4f, 0xe5, 0xb3, 0x9f, 0xa3, 0x92, +0xa6, 0x97, 0xa9, 0x9d, 0xd4, 0x65, 0x33, 0x1e, 0x29, 0x17, 0x21, 0x13, +0x2d, 0x21, 0x45, 0x58, 0xb9, 0xa3, 0xa5, 0x94, 0xa6, 0x97, 0xa8, 0x9c, +0xc5, 0xcf, 0x39, 0x21, 0x2b, 0x19, 0x22, 0x12, 0x2c, 0x1e, 0x3d, 0x44, +0xc0, 0xa8, 0xa6, 0x95, 0xa8, 0x97, 0xa7, 0x9b, 0xbd, 0xbc, 0x3e, 0x25, +0x2e, 0x1a, 0x22, 0x13, 0x2b, 0x1d, 0x3b, 0x3a, 0xd1, 0xad, 0xa8, 0x96, +0xa8, 0x97, 0xa7, 0x9a, 0xb7, 0xb0, 0x43, 0x29, 0x32, 0x1c, 0x24, 0x13, +0x29, 0x1b, 0x39, 0x35, 0xed, 0xb7, 0xab, 0x98, 0xa9, 0x96, 0xa7, 0x99, +0xb2, 0xab, 0x4b, 0x2d, 0x36, 0x1d, 0x25, 0x14, 0x28, 0x19, 0x36, 0x2d, +0x57, 0xbf, 0xad, 0x9a, 0xa9, 0x96, 0xa8, 0x97, 0xae, 0xa4, 0x5a, 0x35, +0x39, 0x1e, 0x27, 0x13, 0x28, 0x16, 0x33, 0x27, 0x4a, 0xdf, 0xb0, 0x9b, +0xab, 0x95, 0xa8, 0x96, 0xad, 0x9f, 0x7b, 0x41, 0x3f, 0x20, 0x28, 0x13, +0x27, 0x14, 0x32, 0x22, 0x3e, 0x46, 0xb5, 0x9d, 0xac, 0x95, 0xa9, 0x95, +0xaa, 0x9b, 0xdb, 0x66, 0x45, 0x25, 0x2b, 0x15, 0x26, 0x12, 0x30, 0x1e, +0x3a, 0x36, 0xbc, 0xa2, 0xac, 0x95, 0xaa, 0x94, 0xa9, 0x99, 0xca, 0xc4, +0x4b, 0x28, 0x2d, 0x17, 0x26, 0x11, 0x2e, 0x1b, 0x37, 0x2e, 0xc5, 0xa9, +0xad, 0x96, 0xab, 0x94, 0xa8, 0x97, 0xc1, 0xb3, 0x53, 0x2e, 0x30, 0x19, +0x26, 0x11, 0x2d, 0x19, 0x34, 0x28, 0xd0, 0xaf, 0xae, 0x98, 0xab, 0x94, +0xa7, 0x95, 0xbc, 0xac, 0x61, 0x38, 0x34, 0x1b, 0x26, 0x10, 0x2d, 0x18, +0x32, 0x22, 0xef, 0xbc, 0xb0, 0x9a, 0xad, 0x95, 0xa8, 0x93, 0xb8, 0xa4, +0xf9, 0x46, 0x39, 0x1d, 0x27, 0x11, 0x2d, 0x16, 0x30, 0x1e, 0x5d, 0xdb, +0xb2, 0x9c, 0xae, 0x95, 0xa7, 0x92, 0xb5, 0x9f, 0xe6, 0x71, 0x3e, 0x20, +0x27, 0x12, 0x2c, 0x15, 0x30, 0x1d, 0x4c, 0x4d, 0xb4, 0x9e, 0xaf, 0x96, +0xa8, 0x92, 0xb0, 0x9d, 0xd9, 0xcd, 0x43, 0x26, 0x2a, 0x13, 0x2c, 0x14, +0x2f, 0x1b, 0x44, 0x3b, 0xb8, 0xa2, 0xb0, 0x97, 0xa8, 0x91, 0xae, 0x9a, +0xcc, 0xb9, 0x4d, 0x2b, 0x2b, 0x14, 0x2c, 0x13, 0x2f, 0x18, 0x3d, 0x2d, +0xbc, 0xa7, 0xb3, 0x99, 0xa9, 0x90, 0xad, 0x97, 0xc8, 0xad, 0x63, 0x38, +0x2d, 0x16, 0x2c, 0x12, 0x2f, 0x17, 0x38, 0x24, 0xc2, 0xae, 0xb6, 0x9b, +0xab, 0x91, 0xab, 0x94, 0xc4, 0xa8, 0xf3, 0x4c, 0x30, 0x19, 0x2c, 0x12, +0x2f, 0x16, 0x35, 0x1f, 0xcb, 0xba, 0xb7, 0x9c, 0xac, 0x92, 0xab, 0x92, +0xbe, 0xa4, 0xdc, 0xee, 0x34, 0x1c, 0x2c, 0x12, 0x2f, 0x14, 0x31, 0x1c, +0xd9, 0xcc, 0xba, 0x9f, 0xae, 0x93, 0xaa, 0x91, 0xbc, 0x9e, 0xcf, 0xc3, +0x39, 0x1e, 0x2c, 0x13, 0x2f, 0x13, 0x2f, 0x19, 0x7e, 0x57, 0xbc, 0xa3, +0xaf, 0x94, 0xa9, 0x90, 0xb9, 0x9c, 0xcb, 0xb3, 0x3d, 0x23, 0x2d, 0x14, +0x2e, 0x13, 0x2e, 0x16, 0x58, 0x37, 0xbf, 0xa9, 0xb1, 0x96, 0xa9, 0x8f, +0xb7, 0x99, 0xc6, 0xaa, 0x44, 0x2b, 0x2d, 0x15, 0x2f, 0x13, 0x2e, 0x14, +0x49, 0x2b, 0xc2, 0xaf, 0xb5, 0x99, 0xa9, 0x8f, 0xb3, 0x97, 0xc3, 0xa5, +0x4f, 0x3a, 0x2e, 0x18, 0x2e, 0x12, 0x2d, 0x12, 0x40, 0x22, 0xc9, 0xbc, +0xb8, 0x9c, 0xaa, 0x90, 0xb0, 0x94, 0xbf, 0x9f, 0x5f, 0x5a, 0x30, 0x1b, +0x2f, 0x14, 0x2d, 0x11, 0x3b, 0x1d, 0xd0, 0xef, 0xbc, 0xa1, 0xac, 0x91, +0xb0, 0x93, 0xbc, 0x9c, 0xe5, 0xbf, 0x33, 0x1e, 0x31, 0x16, 0x2d, 0x11, +0x37, 0x1a, 0xdc, 0x45, 0xc0, 0xa8, 0xad, 0x93, 0xaf, 0x93, 0xbc, 0x9b, +0xcf, 0xb0, 0x37, 0x24, 0x31, 0x18, 0x2e, 0x12, 0x34, 0x18, 0xf2, 0x3a, +0xc5, 0xae, 0xae, 0x96, 0xad, 0x93, 0xba, 0x9a, 0xc9, 0xac, 0x3b, 0x28, +0x31, 0x19, 0x2e, 0x13, 0x31, 0x17, 0x65, 0x34, 0xc8, 0xb3, 0xaf, 0x98, +0xad, 0x93, 0xb7, 0x99, 0xc2, 0xa7, 0x40, 0x2d, 0x32, 0x1a, 0x2f, 0x14, +0x2f, 0x15, 0x4f, 0x2d, 0xce, 0xbc, 0xb3, 0x9a, 0xad, 0x92, 0xb5, 0x98, +0xbd, 0xa2, 0x4a, 0x36, 0x35, 0x1c, 0x30, 0x14, 0x2e, 0x14, 0x48, 0x28, +0xde, 0xd3, 0xb7, 0x9c, 0xad, 0x93, 0xb5, 0x97, 0xba, 0x9e, 0x57, 0x44, +0x38, 0x1e, 0x32, 0x16, 0x2e, 0x13, 0x41, 0x23, 0xf1, 0x61, 0xbb, 0x9f, +0xad, 0x93, 0xb4, 0x97, 0xb9, 0x9d, 0x77, 0xf5, 0x39, 0x1f, 0x34, 0x17, +0x2e, 0x13, 0x3d, 0x1f, 0x6e, 0x49, 0xbf, 0xa3, 0xae, 0x94, 0xb3, 0x97, +0xb8, 0x9b, 0xde, 0xc8, 0x3b, 0x23, 0x35, 0x18, 0x2e, 0x12, 0x3a, 0x1d, +0x60, 0x3d, 0xc5, 0xa7, 0xaf, 0x95, 0xb2, 0x96, 0xb6, 0x99, 0xcf, 0xb9, +0x3e, 0x25, 0x37, 0x19, 0x2e, 0x11, 0x36, 0x1a, 0x52, 0x34, 0xcd, 0xac, +0xb2, 0x96, 0xb2, 0x95, 0xb5, 0x98, 0xc5, 0xad, 0x45, 0x29, 0x39, 0x1a, +0x2f, 0x12, 0x34, 0x18, 0x49, 0x2d, 0xde, 0xb6, 0xb5, 0x97, 0xb2, 0x95, +0xb4, 0x97, 0xbe, 0xa7, 0x4e, 0x2e, 0x3d, 0x1c, 0x2f, 0x12, 0x31, 0x16, +0x45, 0x29, 0x68, 0xc8, 0xb9, 0x9a, 0xb2, 0x94, 0xb5, 0x96, 0xba, 0xa1, +0x5c, 0x39, 0x3f, 0x1d, 0x32, 0x13, 0x2f, 0x13, 0x3f, 0x23, 0x5b, 0xeb, +0xbd, 0x9c, 0xb3, 0x93, 0xb4, 0x94, 0xb8, 0x9d, 0x7e, 0x4c, 0x43, 0x1f, +0x34, 0x13, 0x2f, 0x12, 0x3d, 0x1f, 0x53, 0x4a, 0xc0, 0x9e, 0xb4, 0x94, +0xb4, 0x93, 0xb7, 0x9b, 0xdd, 0xe2, 0x46, 0x22, 0x36, 0x14, 0x2f, 0x11, +0x3a, 0x1c, 0x4b, 0x38, 0xc7, 0xa1, 0xb5, 0x94, 0xb3, 0x93, 0xb4, 0x98, +0xcd, 0xbf, 0x4d, 0x27, 0x38, 0x15, 0x2e, 0xf, 0x37, 0x1a, 0x43, 0x2e, +0xd2, 0xa7, 0xb6, 0x95, 0xb3, 0x93, 0xb1, 0x95, 0xc4, 0xb1, 0x59, 0x2b, +0x3c, 0x17, 0x2f, 0xf, 0x34, 0x18, 0x3e, 0x29, 0xe9, 0xad, 0xb9, 0x96, +0xb3, 0x92, 0xb0, 0x93, 0xbe, 0xaa, 0x6e, 0x31, 0x3f, 0x19, 0x2f, 0xf, +0x33, 0x16, 0x3c, 0x23, 0x6a, 0xb8, 0xbb, 0x97, 0xb4, 0x92, 0xb0, 0x91, +0xbb, 0xa3, 0xf0, 0x3b, 0x42, 0x1b, 0x31, 0xf, 0x32, 0x14, 0x3a, 0x1f, +0x5a, 0xcd, 0xbe, 0x99, 0xb5, 0x92, 0xaf, 0x90, 0xb9, 0x9d, 0xdb, 0x4e, +0x47, 0x1e, 0x32, 0xf, 0x31, 0x11, 0x37, 0x1c, 0x4d, 0x4d, 0xc1, 0x9b, +0xb6, 0x92, 0xaf, 0x8f, 0xb6, 0x9a, 0xce, 0xdb, 0x4e, 0x21, 0x34, 0xf, +0x30, 0xf, 0x35, 0x19, 0x44, 0x35, 0xc9, 0x9d, 0xb7, 0x93, 0xaf, 0x8f, +0xb2, 0x96, 0xc7, 0xbb, 0x5a, 0x27, 0x36, 0x11, 0x2f, 0xe, 0x33, 0x16, +0x3e, 0x2c, 0xd3, 0xa3, 0xb9, 0x94, 0xaf, 0x8e, 0xaf, 0x93, 0xc0, 0xae, +0x6d, 0x2d, 0x39, 0x13, 0x2f, 0xe, 0x30, 0x14, 0x3a, 0x23, 0xe1, 0xa9, +0xbb, 0x96, 0xb0, 0x8e, 0xae, 0x90, 0xbc, 0xa7, 0xe6, 0x38, 0x3b, 0x15, +0x2f, 0xe, 0x30, 0x12, 0x37, 0x1d, 0x6d, 0xb3, 0xbd, 0x97, 0xb0, 0x8f, +0xae, 0x8f, 0xb9, 0xa0, 0xd6, 0x51, 0x3e, 0x18, 0x2f, 0xe, 0x2f, 0x10, +0x34, 0x1a, 0x55, 0xcb, 0xc1, 0x9a, 0xb2, 0x8f, 0xad, 0x8e, 0xb5, 0x9c, +0xca, 0xcb, 0x46, 0x1c, 0x30, 0xe, 0x2e, 0xf, 0x31, 0x16, 0x48, 0x48, +0xc8, 0x9e, 0xb4, 0x91, 0xad, 0x8d, 0xb1, 0x98, 0xc2, 0xb4, 0x4e, 0x22, +0x32, 0xf, 0x2d, 0xf, 0x2f, 0x13, 0x40, 0x30, 0xd0, 0xa3, 0xb5, 0x94, +0xac, 0x8d, 0xaf, 0x95, 0xbc, 0xaa, 0x59, 0x2c, 0x33, 0x12, 0x2d, 0xf, +0x2d, 0x11, 0x3c, 0x28, 0xdb, 0xab, 0xb7, 0x97, 0xab, 0x8d, 0xad, 0x93, +0xb8, 0xa4, 0x7c, 0x3a, 0x35, 0x13, 0x2d, 0xf, 0x2b, 0x10, 0x36, 0x1f, +0xff, 0xb3, 0xba, 0x9a, 0xab, 0x8d, 0xac, 0x90, 0xb4, 0x9e, 0xd6, 0x68, +0x38, 0x17, 0x2d, 0xf, 0x2a, 0xf, 0x32, 0x1b, 0x58, 0xca, 0xbe, 0x9d, +0xac, 0x8e, 0xab, 0x8f, 0xb0, 0x9a, 0xca, 0xbf, 0x3c, 0x1a, 0x2e, 0x10, +0x2a, 0xe, 0x2f, 0x17, 0x4c, 0x52, 0xc3, 0xa0, 0xad, 0x8f, 0xaa, 0x8e, +0xae, 0x98, 0xc2, 0xaf, 0x40, 0x1e, 0x2e, 0x11, 0x29, 0xe, 0x2d, 0x14, +0x42, 0x38, 0xc9, 0xa7, 0xad, 0x91, 0xa9, 0x8e, 0xac, 0x96, 0xbb, 0xa8, +0x47, 0x25, 0x2f, 0x14, 0x28, 0xf, 0x2a, 0x12, 0x3c, 0x2d, 0xd7, 0xae, +0xae, 0x94, 0xa8, 0x8e, 0xab, 0x95, 0xb5, 0xa1, 0x52, 0x2d, 0x31, 0x16, +0x28, 0xf, 0x29, 0xf, 0x37, 0x27, 0xfe, 0xba, 0xb1, 0x97, 0xa8, 0x8e, +0xa9, 0x93, 0xb1, 0x9e, 0x6f, 0x3b, 0x34, 0x18, 0x28, 0x10, 0x27, 0xf, +0x33, 0x20, 0x56, 0xce, 0xb5, 0x9b, 0xa8, 0x8e, 0xa8, 0x92, 0xad, 0x9b, +0xd7, 0x53, 0x38, 0x1b, 0x29, 0x11, 0x25, 0xe, 0x2e, 0x1d, 0x48, 0x56, +0xb9, 0x9e, 0xa9, 0x8f, 0xa7, 0x91, 0xab, 0x99, 0xc9, 0xc7, 0x3c, 0x1d, +0x2a, 0x13, 0x24, 0xe, 0x2c, 0x1a, 0x3f, 0x3e, 0xbe, 0xa4, 0xa9, 0x90, +0xa6, 0x91, 0xa9, 0x97, 0xbe, 0xb3, 0x3f, 0x21, 0x2b, 0x15, 0x23, 0xf, +0x2a, 0x17, 0x39, 0x30, 0xc6, 0xaa, 0xaa, 0x93, 0xa5, 0x91, 0xa6, 0x95, +0xb8, 0xab, 0x4a, 0x29, 0x2d, 0x17, 0x23, 0xf, 0x27, 0x16, 0x33, 0x2a, +0xda, 0xb5, 0xac, 0x95, 0xa6, 0x91, 0xa5, 0x94, 0xb1, 0xa4, 0x5c, 0x2f, +0x2f, 0x1a, 0x23, 0xf, 0x25, 0x14, 0x2f, 0x25, 0x6c, 0xc2, 0xae, 0x98, +0xa6, 0x91, 0xa3, 0x93, 0xad, 0x9f, 0xf0, 0x3b, 0x33, 0x1c, 0x23, 0x10, +0x23, 0x12, 0x2c, 0x20, 0x4c, 0xfc, 0xaf, 0x9a, 0xa6, 0x92, 0xa2, 0x92, +0xa9, 0x9b, 0xd1, 0x55, 0x37, 0x1e, 0x24, 0x11, 0x22, 0x10, 0x29, 0x1d, +0x3f, 0x41, 0xb4, 0x9d, 0xa7, 0x93, 0xa1, 0x91, 0xa7, 0x99, 0xc2, 0xca, +0x3d, 0x23, 0x25, 0x13, 0x21, 0xf, 0x28, 0x1a, 0x38, 0x33, 0xba, 0xa2, +0xa8, 0x94, 0xa1, 0x91, 0xa4, 0x96, 0xbb, 0xb8, 0x46, 0x29, 0x27, 0x15, +0x20, 0xf, 0x26, 0x19, 0x32, 0x2c, 0xc0, 0xa8, 0xa9, 0x96, 0xa1, 0x91, +0xa2, 0x94, 0xb6, 0xaf, 0x51, 0x2d, 0x29, 0x17, 0x1f, 0xf, 0x24, 0x17, +0x2e, 0x27, 0xcd, 0xae, 0xaa, 0x97, 0xa1, 0x91, 0xa0, 0x93, 0xaf, 0xa9, +0x6f, 0x35, 0x2b, 0x19, 0x1f, 0xf, 0x22, 0x16, 0x2b, 0x22, 0xe4, 0xb9, +0xac, 0x98, 0xa2, 0x92, 0x9f, 0x92, 0xad, 0xa3, 0xda, 0x40, 0x2e, 0x1b, +0x1f, 0xf, 0x21, 0x14, 0x29, 0x1f, 0x55, 0xd5, 0xae, 0x9b, 0xa2, 0x93, +0x9e, 0x91, 0xaa, 0x9e, 0xc9, 0x79, 0x32, 0x1e, 0x20, 0x11, 0x20, 0x13, +0x26, 0x1c, 0x43, 0x4d, 0xb2, 0x9e, 0xa4, 0x95, 0x9e, 0x91, 0xa7, 0x9c, +0xbd, 0xc7, 0x3a, 0x24, 0x21, 0x12, 0x20, 0x13, 0x24, 0x1a, 0x38, 0x39, +0xb8, 0xa2, 0xa7, 0x96, 0x9e, 0x91, 0xa4, 0x99, 0xb8, 0xb7, 0x44, 0x2a, +0x23, 0x14, 0x1f, 0x12, 0x22, 0x18, 0x31, 0x2d, 0xbc, 0xa7, 0xa9, 0x98, +0x9e, 0x90, 0xa1, 0x97, 0xb4, 0xad, 0x54, 0x32, 0x25, 0x16, 0x1f, 0x12, +0x21, 0x16, 0x2d, 0x25, 0xc5, 0xaf, 0xaa, 0x9a, 0x9e, 0x90, 0x9f, 0x94, +0xaf, 0xa7, 0xf5, 0x42, 0x27, 0x18, 0x1f, 0x12, 0x1f, 0x15, 0x29, 0x1f, +0xd4, 0xbb, 0xad, 0x9c, 0x9f, 0x92, 0x9e, 0x93, 0xac, 0xa2, 0xcd, 0x6d, +0x2a, 0x1b, 0x1f, 0x12, 0x1f, 0x14, 0x26, 0x1c, 0x68, 0xd0, 0xaf, 0x9e, +0x9f, 0x92, 0x9d, 0x91, 0xa9, 0x9e, 0xc1, 0xc9, 0x2d, 0x1d, 0x1f, 0x13, +0x1f, 0x13, 0x23, 0x1a, 0x4d, 0x55, 0xb4, 0xa2, 0xa1, 0x94, 0x9d, 0x91, +0xa7, 0x9c, 0xb9, 0xb7, 0x33, 0x22, 0x20, 0x14, 0x1f, 0x13, 0x20, 0x18, +0x3d, 0x3b, 0xb9, 0xa8, 0xa4, 0x96, 0x9c, 0x90, 0xa5, 0x9a, 0xb4, 0xae, +0x3b, 0x29, 0x22, 0x16, 0x1f, 0x13, 0x1f, 0x16, 0x37, 0x2e, 0xbe, 0xae, +0xa6, 0x99, 0x9c, 0x91, 0xa3, 0x98, 0xaf, 0xa8, 0x46, 0x32, 0x23, 0x18, +0x1f, 0x13, 0x1e, 0x15, 0x30, 0x28, 0xc7, 0xb8, 0xa9, 0x9b, 0x9c, 0x91, +0xa0, 0x97, 0xac, 0xa3, 0x59, 0x3f, 0x25, 0x1b, 0x1f, 0x14, 0x1e, 0x14, +0x2c, 0x23, 0xd2, 0xc9, 0xab, 0x9e, 0x9c, 0x92, 0x9f, 0x96, 0xaa, 0x9f, +0xdb, 0x6d, 0x27, 0x1d, 0x1f, 0x15, 0x1d, 0x13, 0x28, 0x1e, 0x78, 0x67, +0xae, 0xa1, 0x9d, 0x93, 0x9e, 0x94, 0xa7, 0x9c, 0xc7, 0xc6, 0x29, 0x1f, +0x1f, 0x17, 0x1c, 0x13, 0x24, 0x1c, 0x56, 0x45, 0xb2, 0xa8, 0x9d, 0x95, +0x9d, 0x94, 0xa5, 0x9b, 0xbb, 0xb6, 0x2c, 0x25, 0x20, 0x18, 0x1c, 0x13, +0x20, 0x1a, 0x45, 0x38, 0xb6, 0xad, 0x9e, 0x97, 0x9c, 0x94, 0xa3, 0x9a, +0xb5, 0xae, 0x2f, 0x2b, 0x20, 0x1a, 0x1c, 0x14, 0x1f, 0x19, 0x3c, 0x2f, +0xbc, 0xb5, 0x9f, 0x99, 0x9b, 0x94, 0xa1, 0x99, 0xae, 0xa8, 0x36, 0x31, +0x22, 0x1c, 0x1d, 0x14, 0x1d, 0x17, 0x36, 0x2b, 0xc2, 0xbf, 0xa2, 0x9c, +0x9b, 0x95, 0xa0, 0x98, 0xac, 0xa4, 0x3d, 0x3c, 0x23, 0x1e, 0x1d, 0x16, +0x1d, 0x17, 0x2f, 0x27, 0xd0, 0xda, 0xa5, 0x9e, 0x9b, 0x96, 0x9f, 0x98, +0xa8, 0xa0, 0x4d, 0x4e, 0x25, 0x20, 0x1d, 0x17, 0x1b, 0x16, 0x2b, 0x23, +0xfc, 0x60, 0xa8, 0xa1, 0x9b, 0x97, 0x9e, 0x98, 0xa5, 0x9f, 0xee, 0xe9, +0x28, 0x23, 0x1e, 0x18, 0x1b, 0x16, 0x27, 0x20, 0x51, 0x49, 0xac, 0xa6, +0x9c, 0x98, 0x9d, 0x98, 0xa2, 0x9d, 0xc7, 0xc6, 0x2a, 0x27, 0x1f, 0x1a, +0x1a, 0x16, 0x23, 0x1e, 0x41, 0x3b, 0xb1, 0xab, 0x9c, 0x99, 0x9c, 0x98, +0x9f, 0x9c, 0xb9, 0xb8, 0x2e, 0x2d, 0x1f, 0x1b, 0x19, 0x16, 0x1f, 0x1d, +0x39, 0x31, 0xba, 0xb1, 0x9d, 0x9b, 0x9b, 0x98, 0x9e, 0x9b, 0xaf, 0xaf, +0x32, 0x31, 0x21, 0x1d, 0x19, 0x17, 0x1d, 0x1b, 0x31, 0x2d, 0xc1, 0xb9, +0x9e, 0x9c, 0x9b, 0x98, 0x9d, 0x9a, 0xab, 0xab, 0x3a, 0x38, 0x22, 0x1f, +0x19, 0x17, 0x1c, 0x1b, 0x2d, 0x2b, 0xd4, 0xc5, 0x9f, 0x9e, 0x9a, 0x99, +0x9c, 0x9a, 0xa6, 0xa8, 0x45, 0x40, 0x24, 0x21, 0x1a, 0x18, 0x1a, 0x1a, +0x29, 0x28, 0x65, 0xd8, 0xa3, 0x9f, 0x9a, 0x99, 0x9b, 0x99, 0xa2, 0xa4, +0x63, 0x4f, 0x27, 0x23, 0x1b, 0x18, 0x19, 0x19, 0x25, 0x25, 0x49, 0x6b, +0xa7, 0xa2, 0x9a, 0x99, 0x9a, 0x99, 0x9f, 0xa1, 0xd2, 0x7a, 0x2a, 0x26, +0x1c, 0x19, 0x18, 0x18, 0x22, 0x22, 0x3c, 0x4a, 0xab, 0xa5, 0x9b, 0x99, +0x9a, 0x98, 0x9d, 0x9f, 0xbf, 0xd2, 0x2d, 0x28, 0x1c, 0x1a, 0x17, 0x17, +0x1f, 0x20, 0x35, 0x3f, 0xaf, 0xa8, 0x9b, 0x9a, 0x99, 0x98, 0x9c, 0x9e, +0xb6, 0xc1, 0x31, 0x2b, 0x1e, 0x1a, 0x17, 0x17, 0x1d, 0x1e, 0x2e, 0x36, +0xb8, 0xac, 0x9d, 0x9b, 0x99, 0x98, 0x9a, 0x9c, 0xad, 0xb8, 0x39, 0x2f, +0x1f, 0x1c, 0x17, 0x17, 0x1c, 0x1d, 0x2a, 0x2f, 0xc4, 0xb1, 0x9e, 0x9c, +0x99, 0x98, 0x99, 0x9b, 0xa8, 0xb0, 0x44, 0x35, 0x22, 0x1d, 0x18, 0x17, +0x1a, 0x1c, 0x26, 0x2c, 0xea, 0xb9, 0xa0, 0x9d, 0x9a, 0x98, 0x99, 0x9a, +0xa3, 0xab, 0x5a, 0x3c, 0x25, 0x1f, 0x18, 0x17, 0x19, 0x1b, 0x23, 0x29, +0x4f, 0xc4, 0xa3, 0x9e, 0x9a, 0x98, 0x98, 0x99, 0xa0, 0xa8, 0xda, 0x47, +0x29, 0x20, 0x19, 0x17, 0x18, 0x1a, 0x20, 0x26, 0x3e, 0xd6, 0xa7, 0xa0, +0x9b, 0x99, 0x98, 0x98, 0x9e, 0xa4, 0xc5, 0x59, 0x2d, 0x23, 0x1a, 0x18, +0x18, 0x19, 0x1e, 0x22, 0x36, 0x5f, 0xab, 0xa2, 0x9b, 0x99, 0x98, 0x98, +0x9c, 0xa0, 0xba, 0xde, 0x30, 0x27, 0x1b, 0x18, 0x17, 0x18, 0x1d, 0x1f, +0x2f, 0x44, 0xaf, 0xa6, 0x9c, 0x9a, 0x98, 0x97, 0x9b, 0x9e, 0xb2, 0xc5, +0x37, 0x2a, 0x1d, 0x19, 0x17, 0x17, 0x1c, 0x1e, 0x2b, 0x38, 0xb7, 0xaa, +0x9d, 0x9a, 0x98, 0x97, 0x9a, 0x9c, 0xac, 0xb9, 0x3f, 0x2e, 0x1e, 0x1a, +0x17, 0x17, 0x1b, 0x1c, 0x27, 0x31, 0xc3, 0xae, 0x9f, 0x9c, 0x98, 0x97, +0x99, 0x9b, 0xa8, 0xb1, 0x4f, 0x35, 0x20, 0x1c, 0x17, 0x17, 0x1a, 0x1b, +0x23, 0x2b, 0xdc, 0xb7, 0xa1, 0x9d, 0x99, 0x98, 0x98, 0x9a, 0xa4, 0xac, +0xfa, 0x3e, 0x25, 0x1e, 0x18, 0x17, 0x19, 0x1b, 0x21, 0x28, 0x58, 0xbf, +0xa5, 0x9f, 0x9a, 0x98, 0x98, 0x99, 0xa0, 0xa9, 0xcc, 0x4a, 0x28, 0x20, +0x19, 0x18, 0x19, 0x1a, 0x1f, 0x25, 0x42, 0xd0, 0xa8, 0xa0, 0x9b, 0x99, +0x97, 0x98, 0x9e, 0xa5, 0xbf, 0x64, 0x2b, 0x23, 0x1a, 0x18, 0x18, 0x19, +0x1d, 0x22, 0x39, 0x67, 0xab, 0xa4, 0x9b, 0x99, 0x97, 0x98, 0x9d, 0xa2, +0xb8, 0xd6, 0x2f, 0x27, 0x1a, 0x19, 0x17, 0x19, 0x1c, 0x1f, 0x30, 0x48, +0xae, 0xa8, 0x9c, 0x9a, 0x96, 0x98, 0x9b, 0x9f, 0xb0, 0xc2, 0x35, 0x2a, +0x1c, 0x1a, 0x17, 0x18, 0x1a, 0x1e, 0x2b, 0x3b, 0xb5, 0xab, 0x9d, 0x9b, +0x96, 0x98, 0x9a, 0x9e, 0xab, 0xba, 0x3d, 0x2e, 0x1d, 0x1b, 0x16, 0x18, +0x19, 0x1d, 0x28, 0x33, 0xbd, 0xae, 0x9e, 0x9d, 0x96, 0x98, 0x98, 0x9c, +0xa8, 0xb3, 0x48, 0x35, 0x1e, 0x1c, 0x17, 0x18, 0x18, 0x1c, 0x24, 0x2e, +0xca, 0xb5, 0x9f, 0x9e, 0x97, 0x98, 0x98, 0x9b, 0xa4, 0xae, 0x62, 0x3d, +0x1f, 0x1e, 0x17, 0x18, 0x18, 0x1b, 0x21, 0x2a, 0xea, 0xbd, 0xa2, 0x9f, +0x97, 0x99, 0x97, 0x9a, 0xa0, 0xaa, 0xda, 0x48, 0x23, 0x1f, 0x17, 0x18, +0x17, 0x1a, 0x1f, 0x27, 0x51, 0xc8, 0xa4, 0xa1, 0x98, 0x99, 0x96, 0x99, +0x9e, 0xa8, 0xc6, 0x5d, 0x26, 0x22, 0x17, 0x19, 0x16, 0x1a, 0x1d, 0x24, +0x40, 0xe4, 0xa7, 0xa3, 0x98, 0x9a, 0x95, 0x99, 0x9d, 0xa5, 0xbc, 0xe8, +0x29, 0x25, 0x18, 0x19, 0x15, 0x1a, 0x1b, 0x22, 0x36, 0x59, 0xaa, 0xa5, +0x99, 0x9b, 0x94, 0x98, 0x9b, 0xa2, 0xb4, 0xd1, 0x2e, 0x29, 0x18, 0x19, +0x15, 0x1a, 0x1a, 0x20, 0x2e, 0x42, 0xad, 0xa8, 0x9a, 0x9c, 0x94, 0x98, +0x99, 0x9f, 0xad, 0xc3, 0x35, 0x2d, 0x1a, 0x1b, 0x15, 0x19, 0x18, 0x1f, +0x29, 0x3a, 0xb5, 0xac, 0x9c, 0x9d, 0x94, 0x98, 0x97, 0x9e, 0xa9, 0xba, +0x3e, 0x32, 0x1b, 0x1c, 0x15, 0x1a, 0x17, 0x1e, 0x25, 0x33, 0xbe, 0xaf, +0x9d, 0x9e, 0x95, 0x99, 0x96, 0x9e, 0xa5, 0xb6, 0x4d, 0x38, 0x1d, 0x1d, +0x15, 0x1a, 0x16, 0x1e, 0x21, 0x2e, 0xcf, 0xb6, 0x9f, 0x9f, 0x95, 0x99, +0x95, 0x9c, 0xa0, 0xaf, 0xed, 0x3f, 0x1f, 0x1f, 0x15, 0x1a, 0x15, 0x1d, +0x1e, 0x2b, 0x60, 0xbe, 0xa1, 0xa2, 0x95, 0x9a, 0x94, 0x9c, 0x9e, 0xac, +0xc7, 0x4f, 0x22, 0x21, 0x16, 0x1a, 0x14, 0x1c, 0x1b, 0x27, 0x44, 0xca, +0xa4, 0xa4, 0x96, 0x9a, 0x93, 0x9b, 0x9c, 0xa9, 0xba, 0x71, 0x26, 0x24, +0x16, 0x1a, 0x13, 0x1b, 0x1a, 0x25, 0x37, 0xe1, 0xa9, 0xa6, 0x97, 0x9b, +0x92, 0x9a, 0x99, 0xa6, 0xb0, 0xd5, 0x2a, 0x26, 0x17, 0x1b, 0x13, 0x1b, +0x18, 0x21, 0x2e, 0x59, 0xae, 0xa9, 0x98, 0x9c, 0x92, 0x99, 0x98, 0xa3, +0xab, 0xc4, 0x30, 0x2a, 0x19, 0x1c, 0x13, 0x1b, 0x16, 0x1f, 0x29, 0x45, +0xb5, 0xac, 0x9a, 0x9d, 0x92, 0x99, 0x96, 0xa1, 0xa6, 0xbc, 0x3a, 0x2e, +0x1b, 0x1c, 0x13, 0x1b, 0x15, 0x1f, 0x25, 0x3c, 0xbf, 0xaf, 0x9c, 0x9e, +0x93, 0x99, 0x95, 0x9f, 0xa1, 0xb7, 0x49, 0x32, 0x1c, 0x1d, 0x13, 0x1b, +0x14, 0x1d, 0x20, 0x35, 0xd6, 0xb4, 0x9d, 0x9f, 0x93, 0x99, 0x94, 0x9e, +0x9e, 0xb0, 0x6f, 0x39, 0x1e, 0x1e, 0x14, 0x1b, 0x13, 0x1d, 0x1d, 0x2e, +0x57, 0xbb, 0x9f, 0xa0, 0x93, 0x99, 0x93, 0x9d, 0x9c, 0xac, 0xca, 0x43, +0x20, 0x1f, 0x15, 0x1b, 0x12, 0x1c, 0x1b, 0x2b, 0x40, 0xc5, 0xa4, 0xa3, +0x94, 0x9a, 0x93, 0x9c, 0x9a, 0xa9, 0xb9, 0x59, 0x25, 0x22, 0x16, 0x1b, +0x12, 0x1b, 0x19, 0x27, 0x36, 0xd7, 0xa9, 0xa7, 0x96, 0x9b, 0x92, 0x9b, +0x99, 0xa7, 0xaf, 0xdd, 0x2a, 0x26, 0x17, 0x1c, 0x11, 0x1b, 0x17, 0x24, +0x2e, 0x64, 0xad, 0xaa, 0x97, 0x9c, 0x91, 0x9b, 0x97, 0xa4, 0xaa, 0xc8, +0x2e, 0x29, 0x18, 0x1c, 0x12, 0x1b, 0x16, 0x21, 0x29, 0x4b, 0xb3, 0xac, +0x99, 0x9d, 0x91, 0x9a, 0x96, 0xa2, 0xa6, 0xbd, 0x37, 0x2d, 0x19, 0x1d, +0x12, 0x1b, 0x14, 0x1f, 0x24, 0x3d, 0xbc, 0xb0, 0x9a, 0x9e, 0x91, 0x9a, +0x94, 0xa0, 0xa1, 0xb6, 0x45, 0x33, 0x1b, 0x1e, 0x12, 0x1b, 0x13, 0x1e, +0x1f, 0x36, 0xd0, 0xb7, 0x9c, 0x9f, 0x92, 0x9a, 0x93, 0x9f, 0x9e, 0xaf, +0x77, 0x3b, 0x1d, 0x20, 0x13, 0x1b, 0x12, 0x1d, 0x1d, 0x2f, 0x5a, 0xbe, +0x9f, 0xa2, 0x92, 0x9b, 0x92, 0x9e, 0x9c, 0xad, 0xca, 0x44, 0x1f, 0x22, +0x14, 0x1c, 0x11, 0x1d, 0x1b, 0x2c, 0x41, 0xcb, 0xa2, 0xa5, 0x93, 0x9b, +0x91, 0x9d, 0x9a, 0xa9, 0xba, 0x59, 0x23, 0x25, 0x14, 0x1c, 0x10, 0x1c, +0x19, 0x29, 0x37, 0xe8, 0xa6, 0xa8, 0x94, 0x9c, 0x90, 0x9c, 0x98, 0xa7, +0xb1, 0xe1, 0x27, 0x28, 0x15, 0x1d, 0x10, 0x1c, 0x17, 0x26, 0x2e, 0x55, +0xaa, 0xab, 0x95, 0x9d, 0x90, 0x9c, 0x96, 0xa4, 0xab, 0xc8, 0x2c, 0x2c, +0x17, 0x1e, 0xf, 0x1c, 0x15, 0x23, 0x29, 0x45, 0xaf, 0xaf, 0x96, 0x9e, +0x8f, 0x9c, 0x94, 0xa2, 0xa5, 0xbd, 0x31, 0x2f, 0x18, 0x1f, 0xf, 0x1c, +0x13, 0x21, 0x23, 0x3c, 0xbb, 0xb6, 0x97, 0x9f, 0x8f, 0x9c, 0x92, 0xa1, +0x9f, 0xb6, 0x3c, 0x35, 0x1a, 0x21, 0xf, 0x1c, 0x11, 0x1f, 0x1f, 0x35, +0xce, 0xbd, 0x9a, 0xa1, 0x8f, 0x9c, 0x91, 0x9f, 0x9c, 0xaf, 0x56, 0x3d, +0x1c, 0x24, 0xf, 0x1c, 0xf, 0x1f, 0x1c, 0x2f, 0x59, 0xc8, 0x9c, 0xa4, +0x90, 0x9d, 0x90, 0x9f, 0x9a, 0xac, 0xd2, 0x49, 0x1e, 0x27, 0x11, 0x1d, +0xf, 0x1e, 0x1a, 0x2d, 0x3d, 0xde, 0x9f, 0xa7, 0x91, 0x9d, 0x8f, 0x9e, +0x97, 0xaa, 0xbc, 0x61, 0x21, 0x2a, 0x12, 0x1e, 0xe, 0x1d, 0x17, 0x2a, +0x32, 0x5e, 0xa3, 0xab, 0x92, 0x9e, 0x8f, 0x9e, 0x95, 0xa7, 0xaf, 0xd8, +0x27, 0x2d, 0x13, 0x1f, 0xe, 0x1d, 0x15, 0x27, 0x2a, 0x49, 0xa9, 0xae, +0x93, 0x9f, 0x8f, 0x9e, 0x92, 0xa5, 0xa8, 0xc5, 0x2d, 0x30, 0x15, 0x20, +0xe, 0x1d, 0x12, 0x25, 0x24, 0x3f, 0xb1, 0xb3, 0x95, 0xa1, 0x8e, 0x9e, +0x91, 0xa4, 0xa1, 0xbd, 0x36, 0x36, 0x17, 0x22, 0xe, 0x1e, 0x10, 0x23, +0x1f, 0x39, 0xbe, 0xb9, 0x97, 0xa3, 0x8e, 0x9e, 0x8f, 0xa3, 0x9d, 0xb7, +0x46, 0x3d, 0x19, 0x25, 0xe, 0x1e, 0xf, 0x22, 0x1c, 0x34, 0xe5, 0xc0, +0x9a, 0xa6, 0x8e, 0x9f, 0x8f, 0xa2, 0x9a, 0xb1, 0xe4, 0x47, 0x1b, 0x27, +0xf, 0x1f, 0xe, 0x21, 0x19, 0x2f, 0x48, 0xcd, 0x9c, 0xa9, 0x8f, 0x9f, +0x8e, 0xa1, 0x97, 0xae, 0xbf, 0x59, 0x1e, 0x2a, 0xf, 0x1f, 0xe, 0x20, +0x16, 0x2d, 0x36, 0xec, 0x9f, 0xac, 0x8f, 0xa0, 0x8e, 0xa0, 0x94, 0xac, +0xb2, 0xe8, 0x23, 0x2d, 0x10, 0x21, 0xd, 0x20, 0x14, 0x2b, 0x2c, 0x59, +0xa5, 0xaf, 0x91, 0xa2, 0x8d, 0xa0, 0x92, 0xaa, 0xa9, 0xce, 0x29, 0x30, +0x12, 0x23, 0xd, 0x20, 0x11, 0x29, 0x25, 0x4a, 0xac, 0xb4, 0x93, 0xa4, +0x8d, 0xa0, 0x90, 0xa8, 0xa2, 0xc3, 0x2f, 0x36, 0x14, 0x25, 0xd, 0x20, +0xf, 0x27, 0x1f, 0x3f, 0xb6, 0xb9, 0x95, 0xa5, 0x8d, 0xa0, 0x8f, 0xa7, +0x9e, 0xbc, 0x3d, 0x3b, 0x17, 0x27, 0xd, 0x21, 0xe, 0x26, 0x1c, 0x3a, +0xca, 0xbf, 0x98, 0xa7, 0x8e, 0xa1, 0x8e, 0xa6, 0x9b, 0xb7, 0x63, 0x42, +0x1a, 0x29, 0xe, 0x21, 0xe, 0x25, 0x19, 0x36, 0x55, 0xc9, 0x9a, 0xaa, +0x8e, 0xa1, 0x8d, 0xa5, 0x98, 0xb3, 0xc9, 0x4c, 0x1d, 0x2b, 0xe, 0x22, +0xd, 0x24, 0x16, 0x32, 0x3a, 0xd5, 0x9d, 0xac, 0x8f, 0xa2, 0x8d, 0xa4, +0x95, 0xaf, 0xb7, 0x5d, 0x20, 0x2d, 0xf, 0x23, 0xd, 0x23, 0x14, 0x2f, +0x2e, 0xfa, 0xa1, 0xae, 0x90, 0xa4, 0x8d, 0xa4, 0x93, 0xad, 0xad, 0xeb, +0x27, 0x2f, 0x11, 0x25, 0xd, 0x23, 0x12, 0x2d, 0x28, 0x58, 0xa8, 0xb2, +0x93, 0xa5, 0x8d, 0xa4, 0x91, 0xac, 0xa7, 0xd2, 0x2d, 0x34, 0x13, 0x26, +0xd, 0x23, 0x11, 0x2c, 0x22, 0x4b, 0xae, 0xb6, 0x95, 0xa7, 0x8e, 0xa4, +0x90, 0xab, 0xa1, 0xc8, 0x37, 0x39, 0x15, 0x28, 0xd, 0x24, 0x10, 0x2b, +0x1e, 0x42, 0xba, 0xbb, 0x97, 0xa8, 0x8e, 0xa4, 0x8f, 0xa9, 0x9e, 0xbe, +0x44, 0x3d, 0x18, 0x2a, 0xe, 0x23, 0xf, 0x29, 0x1c, 0x3c, 0xcb, 0xc2, +0x99, 0xaa, 0x8e, 0xa4, 0x8e, 0xa8, 0x9b, 0xb9, 0x6e, 0x45, 0x1a, 0x2b, +0xe, 0x24, 0xe, 0x27, 0x19, 0x37, 0x5a, 0xcd, 0x9b, 0xac, 0x8f, 0xa5, +0x8e, 0xa7, 0x99, 0xb4, 0xca, 0x4e, 0x1d, 0x2d, 0xf, 0x25, 0xe, 0x26, +0x17, 0x34, 0x3e, 0xdd, 0x9e, 0xad, 0x8f, 0xa5, 0x8e, 0xa7, 0x96, 0xb1, +0xb9, 0x5e, 0x1f, 0x2f, 0xf, 0x26, 0xe, 0x26, 0x15, 0x31, 0x32, 0x74, +0xa1, 0xaf, 0x91, 0xa6, 0x8e, 0xa6, 0x94, 0xae, 0xaf, 0xef, 0x25, 0x32, +0x11, 0x27, 0xd, 0x25, 0x14, 0x2f, 0x2b, 0x56, 0xa7, 0xb4, 0x92, 0xa6, +0x8e, 0xa6, 0x92, 0xac, 0xa9, 0xd3, 0x2a, 0x36, 0x13, 0x28, 0xd, 0x24, +0x12, 0x2d, 0x25, 0x49, 0xad, 0xb8, 0x94, 0xa8, 0x8e, 0xa6, 0x90, 0xab, +0xa3, 0xc7, 0x30, 0x3a, 0x15, 0x29, 0xd, 0x24, 0x10, 0x2b, 0x1f, 0x40, +0xb6, 0xbd, 0x95, 0xa9, 0x8e, 0xa6, 0x8f, 0xa9, 0x9e, 0xbf, 0x3c, 0x3f, +0x17, 0x2b, 0xd, 0x24, 0xf, 0x2a, 0x1d, 0x3c, 0xc5, 0xc4, 0x97, 0xaa, +0x8e, 0xa6, 0x8e, 0xa8, 0x9c, 0xba, 0x55, 0x47, 0x1a, 0x2d, 0xe, 0x25, +0xe, 0x29, 0x1a, 0x38, 0x68, 0xce, 0x9a, 0xac, 0x8f, 0xa6, 0x8e, 0xa7, +0x99, 0xb6, 0xcf, 0x4f, 0x1c, 0x2e, 0xe, 0x25, 0xe, 0x28, 0x17, 0x34, +0x40, 0xdf, 0x9c, 0xae, 0x8f, 0xa7, 0x8d, 0xa7, 0x96, 0xb2, 0xbc, 0x60, +0x1f, 0x31, 0xf, 0x26, 0xd, 0x27, 0x15, 0x31, 0x32, 0x67, 0x9f, 0xb0, +0x90, 0xa8, 0x8d, 0xa6, 0x94, 0xaf, 0xaf, 0xe7, 0x25, 0x35, 0x10, 0x27, +0xd, 0x26, 0x13, 0x2e, 0x2b, 0x4f, 0xa5, 0xb4, 0x92, 0xa9, 0x8d, 0xa6, +0x92, 0xad, 0xa9, 0xd2, 0x2b, 0x3a, 0x12, 0x28, 0xd, 0x26, 0x12, 0x2d, +0x25, 0x46, 0xab, 0xb8, 0x94, 0xaa, 0x8d, 0xa6, 0x90, 0xab, 0xa4, 0xc8, +0x32, 0x3e, 0x14, 0x29, 0xd, 0x25, 0x10, 0x2c, 0x1f, 0x3e, 0xb2, 0xbc, +0x96, 0xab, 0x8e, 0xa6, 0x8f, 0xaa, 0x9f, 0xc0, 0x3d, 0x44, 0x16, 0x2b, +0xe, 0x26, 0xf, 0x2b, 0x1c, 0x3a, 0xbf, 0xc3, 0x98, 0xac, 0x8e, 0xa6, +0x8e, 0xa8, 0x9c, 0xbc, 0x59, 0x4c, 0x19, 0x2c, 0xe, 0x25, 0xf, 0x2a, +0x1a, 0x37, 0xe6, 0xcc, 0x9a, 0xad, 0x8f, 0xa7, 0x8e, 0xa8, 0x9a, 0xb8, +0xcb, 0x59, 0x1c, 0x2e, 0xe, 0x26, 0xe, 0x29, 0x17, 0x32, 0x45, 0xda, +0x9d, 0xaf, 0x8f, 0xa7, 0x8d, 0xa6, 0x97, 0xb4, 0xba, 0x75, 0x1f, 0x31, +0xf, 0x26, 0xe, 0x28, 0x15, 0x2f, 0x34, 0x70, 0xa0, 0xb1, 0x91, 0xa8, +0x8d, 0xa6, 0x95, 0xaf, 0xaf, 0xde, 0x26, 0x35, 0x11, 0x27, 0xe, 0x27, +0x14, 0x2e, 0x2b, 0x53, 0xa6, 0xb4, 0x93, 0xa9, 0x8e, 0xa6, 0x93, 0xae, +0xaa, 0xd0, 0x2c, 0x39, 0x13, 0x28, 0xe, 0x26, 0x13, 0x2d, 0x24, 0x48, +0xad, 0xb8, 0x95, 0xaa, 0x8e, 0xa6, 0x91, 0xac, 0xa4, 0xc9, 0x36, 0x3d, +0x16, 0x29, 0xe, 0x26, 0x11, 0x2c, 0x1f, 0x3f, 0xb8, 0xbc, 0x98, 0xab, +0x8f, 0xa6, 0x8f, 0xaa, 0x9f, 0xc0, 0x47, 0x43, 0x19, 0x2a, 0xe, 0x25, +0x10, 0x2a, 0x1c, 0x3b, 0xca, 0xc1, 0x9a, 0xac, 0x8f, 0xa6, 0x8f, 0xa9, +0x9c, 0xbc, 0xef, 0x4c, 0x1b, 0x2c, 0xf, 0x25, 0xf, 0x29, 0x1a, 0x36, +0x5c, 0xca, 0x9d, 0xad, 0x90, 0xa6, 0x8f, 0xa7, 0x9a, 0xb7, 0xc0, 0x59, +0x1e, 0x2e, 0x10, 0x25, 0xf, 0x28, 0x18, 0x32, 0x3d, 0xd7, 0xa0, 0xae, +0x92, 0xa6, 0x8f, 0xa6, 0x98, 0xb3, 0xb5, 0x72, 0x24, 0x2f, 0x12, 0x26, +0xf, 0x27, 0x16, 0x2f, 0x31, 0xf5, 0xa6, 0xb0, 0x94, 0xa7, 0x8f, 0xa5, +0x97, 0xb0, 0xad, 0xdf, 0x2a, 0x32, 0x14, 0x26, 0x10, 0x26, 0x15, 0x2d, +0x2b, 0x5c, 0xab, 0xb3, 0x97, 0xa7, 0x8f, 0xa4, 0x95, 0xae, 0xa9, 0xcf, +0x30, 0x36, 0x16, 0x27, 0x10, 0x26, 0x14, 0x2c, 0x26, 0x4b, 0xb0, 0xb7, +0x99, 0xa9, 0x8f, 0xa4, 0x94, 0xac, 0xa4, 0xc6, 0x3c, 0x3b, 0x18, 0x28, +0x11, 0x25, 0x13, 0x2a, 0x21, 0x41, 0xbb, 0xbb, 0x9b, 0xaa, 0x90, 0xa3, +0x93, 0xaa, 0xa0, 0xbf, 0x51, 0x3f, 0x1a, 0x28, 0x12, 0x25, 0x13, 0x29, +0x1e, 0x3c, 0xce, 0xbe, 0x9d, 0xab, 0x92, 0xa4, 0x92, 0xa8, 0x9e, 0xbb, +0xd8, 0x47, 0x1d, 0x2a, 0x13, 0x24, 0x12, 0x27, 0x1c, 0x37, 0x61, 0xc7, +0xa0, 0xac, 0x93, 0xa4, 0x92, 0xa7, 0x9c, 0xb6, 0xc0, 0x52, 0x20, 0x2b, +0x14, 0x25, 0x13, 0x26, 0x1a, 0x32, 0x44, 0xd0, 0xa5, 0xae, 0x95, 0xa4, +0x92, 0xa6, 0x9b, 0xb2, 0xb6, 0x6f, 0x25, 0x2d, 0x16, 0x25, 0x13, 0x25, +0x18, 0x2e, 0x38, 0xe9, 0xa9, 0xaf, 0x97, 0xa5, 0x91, 0xa4, 0x9a, 0xaf, +0xae, 0xde, 0x2a, 0x2f, 0x17, 0x25, 0x13, 0x24, 0x17, 0x2c, 0x2f, 0x5d, +0xad, 0xb2, 0x98, 0xa5, 0x92, 0xa3, 0x98, 0xac, 0xaa, 0xcd, 0x30, 0x34, +0x18, 0x25, 0x13, 0x23, 0x16, 0x2a, 0x29, 0x4b, 0xb4, 0xb6, 0x9b, 0xa7, +0x92, 0xa2, 0x97, 0xaa, 0xa7, 0xc4, 0x3b, 0x39, 0x1a, 0x26, 0x14, 0x23, +0x16, 0x29, 0x25, 0x3f, 0xbc, 0xba, 0x9c, 0xa8, 0x93, 0xa2, 0x96, 0xa8, +0xa4, 0xbd, 0x4d, 0x3e, 0x1c, 0x27, 0x15, 0x23, 0x15, 0x27, 0x20, 0x3a, +0xcc, 0xbe, 0x9f, 0xa9, 0x94, 0xa2, 0x95, 0xa6, 0xa0, 0xb9, 0xe7, 0x47, +0x1e, 0x29, 0x15, 0x22, 0x15, 0x26, 0x1e, 0x34, 0x6a, 0xc6, 0xa2, 0xab, +0x96, 0xa2, 0x95, 0xa4, 0x9e, 0xb4, 0xc3, 0x55, 0x22, 0x2a, 0x17, 0x22, +0x15, 0x25, 0x1c, 0x2f, 0x47, 0xd3, 0xa7, 0xad, 0x97, 0xa3, 0x94, 0xa3, +0x9d, 0xaf, 0xb9, 0x7c, 0x27, 0x2d, 0x18, 0x23, 0x15, 0x24, 0x1b, 0x2d, +0x3a, 0xf8, 0xab, 0xaf, 0x99, 0xa4, 0x94, 0xa2, 0x9b, 0xad, 0xb0, 0xd8, +0x2c, 0x2f, 0x19, 0x24, 0x15, 0x23, 0x19, 0x2b, 0x30, 0x58, 0xb0, 0xb2, +0x9b, 0xa5, 0x94, 0xa2, 0x9a, 0xab, 0xab, 0xc9, 0x33, 0x34, 0x1b, 0x25, +0x16, 0x23, 0x18, 0x29, 0x2b, 0x49, 0xba, 0xb7, 0x9c, 0xa6, 0x95, 0xa1, +0x99, 0xaa, 0xa7, 0xbf, 0x3e, 0x3a, 0x1c, 0x26, 0x16, 0x23, 0x17, 0x27, +0x26, 0x3e, 0xc6, 0xbc, 0x9e, 0xa8, 0x95, 0xa1, 0x98, 0xa8, 0xa3, 0xba, +0x53, 0x40, 0x1e, 0x28, 0x17, 0x23, 0x16, 0x26, 0x22, 0x39, 0xe7, 0xc2, +0xa2, 0xaa, 0x96, 0xa1, 0x97, 0xa6, 0x9f, 0xb6, 0xd7, 0x4b, 0x21, 0x29, +0x18, 0x23, 0x16, 0x25, 0x1f, 0x33, 0x50, 0xcb, 0xa6, 0xac, 0x97, 0xa2, +0x97, 0xa5, 0x9e, 0xb1, 0xc0, 0x5d, 0x26, 0x2b, 0x19, 0x24, 0x16, 0x24, +0x1d, 0x2f, 0x3f, 0xdc, 0xab, 0xae, 0x98, 0xa3, 0x97, 0xa4, 0x9d, 0xaf, +0xb6, 0xe9, 0x2a, 0x2d, 0x1b, 0x25, 0x16, 0x23, 0x1c, 0x2d, 0x37, 0x78, +0xaf, 0xb2, 0x9a, 0xa4, 0x97, 0xa4, 0x9b, 0xad, 0xae, 0xcf, 0x2f, 0x30, +0x1c, 0x26, 0x16, 0x23, 0x1a, 0x2b, 0x2f, 0x57, 0xb9, 0xb6, 0x9c, 0xa5, +0x97, 0xa3, 0x9b, 0xac, 0xaa, 0xc6, 0x37, 0x34, 0x1e, 0x27, 0x17, 0x23, +0x19, 0x29, 0x2b, 0x4a, 0xc4, 0xba, 0x9e, 0xa7, 0x97, 0xa3, 0x9a, 0xaa, +0xa6, 0xbe, 0x42, 0x39, 0x1f, 0x28, 0x18, 0x24, 0x18, 0x28, 0x27, 0x41, +0xd7, 0xbe, 0xa0, 0xa9, 0x98, 0xa2, 0x99, 0xa9, 0xa3, 0xba, 0x5e, 0x3f, +0x22, 0x29, 0x19, 0x24, 0x18, 0x27, 0x23, 0x3b, 0x5e, 0xc4, 0xa5, 0xab, +0x99, 0xa3, 0x99, 0xa8, 0xa0, 0xb7, 0xd1, 0x48, 0x26, 0x2a, 0x1a, 0x25, +0x18, 0x26, 0x20, 0x37, 0x48, 0xcb, 0xaa, 0xad, 0x9a, 0xa3, 0x99, 0xa7, +0x9f, 0xb4, 0xbe, 0x56, 0x2a, 0x2c, 0x1b, 0x25, 0x18, 0x25, 0x1e, 0x32, +0x3d, 0xd4, 0xae, 0xaf, 0x9b, 0xa4, 0x99, 0xa6, 0x9e, 0xb1, 0xb5, 0x7d, +0x2e, 0x2d, 0x1d, 0x26, 0x18, 0x25, 0x1d, 0x2f, 0x35, 0xea, 0xb5, 0xb2, +0x9d, 0xa5, 0x99, 0xa5, 0x9d, 0xae, 0xae, 0xd7, 0x35, 0x2f, 0x1e, 0x27, +0x19, 0x24, 0x1c, 0x2c, 0x2e, 0x5f, 0xbe, 0xb6, 0x9e, 0xa5, 0x99, 0xa4, +0x9c, 0xad, 0xaa, 0xc9, 0x3d, 0x33, 0x20, 0x28, 0x1a, 0x24, 0x1b, 0x2a, +0x2b, 0x4f, 0xcb, 0xba, 0xa1, 0xa7, 0x9a, 0xa4, 0x9b, 0xab, 0xa7, 0xc0, +0x4b, 0x37, 0x23, 0x28, 0x1a, 0x24, 0x1a, 0x29, 0x28, 0x46, 0xec, 0xbd, +0xa4, 0xa8, 0x9a, 0xa3, 0x9b, 0xaa, 0xa4, 0xbb, 0x77, 0x3b, 0x26, 0x29, +0x1b, 0x24, 0x1a, 0x27, 0x25, 0x3e, 0x51, 0xc3, 0xa8, 0xa9, 0x9b, 0xa3, +0x9b, 0xa9, 0xa1, 0xb7, 0xcd, 0x41, 0x2a, 0x2a, 0x1c, 0x24, 0x1a, 0x26, +0x22, 0x3a, 0x41, 0xcc, 0xac, 0xab, 0x9c, 0xa3, 0x9b, 0xa8, 0x9f, 0xb3, +0xbe, 0x4c, 0x2e, 0x2c, 0x1e, 0x25, 0x1a, 0x25, 0x20, 0x35, 0x39, 0xda, +0xb2, 0xad, 0x9d, 0xa4, 0x9b, 0xa7, 0x9e, 0xaf, 0xb6, 0x5f, 0x34, 0x2e, +0x1f, 0x26, 0x1a, 0x24, 0x1e, 0x30, 0x32, 0x7b, 0xbb, 0xb0, 0x9f, 0xa4, +0x9b, 0xa6, 0x9d, 0xad, 0xaf, 0xe3, 0x3c, 0x2f, 0x22, 0x27, 0x1a, 0x23, +0x1d, 0x2e, 0x2d, 0x57, 0xc6, 0xb4, 0xa1, 0xa5, 0x9b, 0xa5, 0x9d, 0xab, +0xab, 0xcd, 0x46, 0x34, 0x25, 0x28, 0x1b, 0x23, 0x1d, 0x2b, 0x2a, 0x49, +0xda, 0xb9, 0xa4, 0xa6, 0x9c, 0xa4, 0x9c, 0xaa, 0xa8, 0xc1, 0x5b, 0x39, +0x28, 0x29, 0x1c, 0x23, 0x1c, 0x29, 0x28, 0x3f, 0x5d, 0xbf, 0xa7, 0xa8, +0x9d, 0xa4, 0x9c, 0xa8, 0xa5, 0xbb, 0xdf, 0x3e, 0x2b, 0x2b, 0x1d, 0x23, +0x1b, 0x27, 0x25, 0x3b, 0x49, 0xc8, 0xab, 0xaa, 0x9d, 0xa4, 0x9c, 0xa7, +0xa2, 0xb6, 0xc9, 0x47, 0x2e, 0x2c, 0x1e, 0x24, 0x1b, 0x26, 0x23, 0x36, +0x3d, 0xd5, 0xaf, 0xac, 0x9e, 0xa4, 0x9c, 0xa6, 0xa0, 0xb1, 0xbd, 0x54, +0x32, 0x2e, 0x1f, 0x25, 0x1b, 0x25, 0x21, 0x32, 0x38, 0xf1, 0xb5, 0xae, +0x9f, 0xa5, 0x9c, 0xa5, 0x9f, 0xae, 0xb6, 0xfb, 0x38, 0x2f, 0x21, 0x26, +0x1c, 0x24, 0x1f, 0x2e, 0x32, 0x5b, 0xbd, 0xb3, 0xa1, 0xa5, 0x9d, 0xa5, +0x9f, 0xac, 0xaf, 0xd2, 0x3e, 0x34, 0x25, 0x27, 0x1c, 0x24, 0x1f, 0x2c, +0x2f, 0x4d, 0xcb, 0xb8, 0xa4, 0xa7, 0x9d, 0xa5, 0x9e, 0xab, 0xac, 0xc6, +0x4a, 0x38, 0x27, 0x29, 0x1d, 0x24, 0x1e, 0x2a, 0x2c, 0x44, 0xeb, 0xbd, +0xa7, 0xa8, 0x9e, 0xa5, 0x9e, 0xaa, 0xa9, 0xbd, 0x61, 0x3c, 0x2a, 0x2a, +0x1e, 0x24, 0x1d, 0x29, 0x29, 0x3d, 0x55, 0xc5, 0xaa, 0xaa, 0x9e, 0xa5, +0x9e, 0xa9, 0xa6, 0xb8, 0xda, 0x44, 0x2d, 0x2c, 0x1f, 0x25, 0x1d, 0x27, +0x27, 0x39, 0x46, 0xd0, 0xad, 0xac, 0x9f, 0xa5, 0x9e, 0xa8, 0xa4, 0xb4, +0xc8, 0x4f, 0x31, 0x2e, 0x20, 0x26, 0x1d, 0x26, 0x25, 0x35, 0x3c, 0xe8, +0xb3, 0xaf, 0xa1, 0xa6, 0x9e, 0xa7, 0xa2, 0xb0, 0xbd, 0x69, 0x37, 0x31, +0x22, 0x27, 0x1d, 0x26, 0x24, 0x31, 0x37, 0x61, 0xba, 0xb2, 0xa3, 0xa7, +0x9e, 0xa7, 0xa1, 0xae, 0xb7, 0xdf, 0x3d, 0x34, 0x25, 0x28, 0x1d, 0x25, +0x22, 0x2e, 0x31, 0x4f, 0xc3, 0xb7, 0xa5, 0xa8, 0x9f, 0xa7, 0xa0, 0xac, +0xb1, 0xcd, 0x47, 0x39, 0x28, 0x2a, 0x1e, 0x25, 0x21, 0x2d, 0x2e, 0x46, +0xd1, 0xbc, 0xa7, 0xa9, 0x9f, 0xa7, 0x9f, 0xab, 0xad, 0xc3, 0x55, 0x3d, +0x2b, 0x2b, 0x1e, 0x26, 0x20, 0x2b, 0x2c, 0x3f, 0x7a, 0xc3, 0xaa, 0xab, +0xa0, 0xa7, 0x9f, 0xaa, 0xab, 0xbd, 0xef, 0x43, 0x2e, 0x2d, 0x1f, 0x26, +0x20, 0x2a, 0x2a, 0x3b, 0x4f, 0xcd, 0xad, 0xad, 0xa2, 0xa7, 0x9f, 0xaa, +0xa8, 0xb8, 0xcf, 0x4c, 0x33, 0x2f, 0x21, 0x27, 0x1f, 0x29, 0x28, 0x38, +0x42, 0xdd, 0xb1, 0xaf, 0xa4, 0xa8, 0x9f, 0xa9, 0xa6, 0xb4, 0xc4, 0x5b, +0x38, 0x32, 0x23, 0x28, 0x1f, 0x28, 0x27, 0x34, 0x3b, 0x73, 0xb7, 0xb2, +0xa5, 0xa9, 0x9f, 0xa9, 0xa5, 0xb1, 0xbd, 0xff, 0x3e, 0x36, 0x25, 0x29, +0x1f, 0x28, 0x26, 0x32, 0x36, 0x57, 0xbd, 0xb5, 0xa7, 0xaa, 0xa0, 0xa9, +0xa3, 0xaf, 0xb9, 0xdc, 0x46, 0x39, 0x28, 0x2a, 0x20, 0x28, 0x25, 0x30, +0x32, 0x4c, 0xc5, 0xba, 0xa9, 0xaa, 0xa1, 0xa9, 0xa3, 0xad, 0xb4, 0xce, +0x4f, 0x3c, 0x2a, 0x2c, 0x20, 0x27, 0x25, 0x2f, 0x2f, 0x45, 0xd5, 0xbe, +0xab, 0xab, 0xa3, 0xa9, 0xa2, 0xac, 0xb0, 0xc6, 0x64, 0x3f, 0x2e, 0x2e, +0x22, 0x27, 0x24, 0x2d, 0x2d, 0x3f, 0x6d, 0xc6, 0xad, 0xac, 0xa5, 0xaa, +0xa2, 0xab, 0xad, 0xbe, 0xe6, 0x45, 0x33, 0x2f, 0x23, 0x28, 0x24, 0x2c, +0x2c, 0x3c, 0x4e, 0xd2, 0xb0, 0xae, 0xa7, 0xaa, 0xa3, 0xab, 0xab, 0xba, +0xd2, 0x4c, 0x38, 0x33, 0x25, 0x28, 0x24, 0x2b, 0x2b, 0x3a, 0x44, 0xe8, +0xb5, 0xaf, 0xa8, 0xaa, 0xa3, 0xaa, 0xaa, 0xb6, 0xc9, 0x57, 0x3d, 0x36, +0x27, 0x28, 0x24, 0x2a, 0x2a, 0x37, 0x3d, 0x62, 0xba, 0xb2, 0xaa, 0xab, +0xa4, 0xaa, 0xa8, 0xb1, 0xc0, 0x6c, 0x44, 0x39, 0x29, 0x2a, 0x24, 0x29, +0x2a, 0x34, 0x39, 0x4f, 0xbf, 0xb5, 0xab, 0xab, 0xa5, 0xa9, 0xa7, 0xae, +0xbc, 0xdf, 0x4e, 0x3c, 0x2b, 0x2a, 0x25, 0x28, 0x29, 0x31, 0x34, 0x47, +0xc9, 0xb9, 0xad, 0xac, 0xa6, 0xa9, 0xa6, 0xad, 0xb8, 0xcf, 0x5d, 0x3f, +0x2e, 0x2c, 0x25, 0x28, 0x28, 0x2f, 0x31, 0x3f, 0xd8, 0xbe, 0xaf, 0xac, +0xa7, 0xa9, 0xa6, 0xab, 0xb4, 0xc6, 0xf4, 0x46, 0x31, 0x2d, 0x26, 0x27, +0x28, 0x2d, 0x2f, 0x3b, 0x7b, 0xc6, 0xb2, 0xad, 0xa9, 0xa9, 0xa6, 0xaa, +0xb1, 0xbe, 0xda, 0x4e, 0x35, 0x2f, 0x27, 0x27, 0x28, 0x2c, 0x2e, 0x37, +0x58, 0xd1, 0xb6, 0xaf, 0xaa, 0xaa, 0xa6, 0xa8, 0xaf, 0xb9, 0xce, 0x5e, +0x3a, 0x33, 0x28, 0x27, 0x28, 0x2b, 0x2d, 0x33, 0x4a, 0xef, 0xb9, 0xb1, +0xac, 0xab, 0xa6, 0xa8, 0xae, 0xb5, 0xc7, 0xee, 0x3f, 0x37, 0x2a, 0x28, +0x29, 0x2a, 0x2c, 0x30, 0x41, 0x59, 0xbe, 0xb5, 0xad, 0xac, 0xa6, 0xa7, +0xac, 0xb0, 0xc0, 0xd4, 0x48, 0x3c, 0x2b, 0x29, 0x29, 0x2a, 0x2b, 0x2e, +0x3c, 0x49, 0xc4, 0xb9, 0xaf, 0xad, 0xa7, 0xa7, 0xab, 0xae, 0xbc, 0xc9, +0x54, 0x43, 0x2d, 0x2a, 0x29, 0x29, 0x2b, 0x2c, 0x38, 0x3e, 0xcc, 0xbe, +0xb2, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xb9, 0xc0, 0x6b, 0x4d, 0x2f, 0x2c, +0x2a, 0x29, 0x2b, 0x2b, 0x34, 0x39, 0xda, 0xc6, 0xb5, 0xb0, 0xa9, 0xa7, +0xaa, 0xaa, 0xb7, 0xbc, 0xe2, 0x5f, 0x33, 0x2e, 0x2a, 0x29, 0x2b, 0x2b, +0x31, 0x34, 0xfa, 0xd0, 0xb8, 0xb2, 0xab, 0xa9, 0xa9, 0xa8, 0xb5, 0xb8, +0xd4, 0xeb, 0x38, 0x31, 0x2b, 0x29, 0x2b, 0x2a, 0x2f, 0x30, 0x5a, 0xef, +0xbb, 0xb6, 0xad, 0xaa, 0xa9, 0xa7, 0xb2, 0xb4, 0xcb, 0xd3, 0x3d, 0x37, +0x2c, 0x29, 0x2b, 0x2a, 0x2e, 0x2e, 0x4b, 0x58, 0xbe, 0xb9, 0xae, 0xac, +0xa9, 0xa7, 0xaf, 0xb0, 0xc4, 0xc9, 0x45, 0x3d, 0x2d, 0x2a, 0x2c, 0x2a, +0x2d, 0x2c, 0x42, 0x48, 0xc4, 0xbd, 0xb1, 0xad, 0xa9, 0xa7, 0xae, 0xae, +0xbf, 0xc0, 0x4f, 0x45, 0x2e, 0x2c, 0x2c, 0x2a, 0x2d, 0x2b, 0x3d, 0x3e, +0xcb, 0xc4, 0xb4, 0xaf, 0xaa, 0xa7, 0xad, 0xac, 0xbd, 0xbc, 0x5f, 0x50, +0x31, 0x2d, 0x2c, 0x2a, 0x2c, 0x2a, 0x39, 0x39, 0xd6, 0xcd, 0xb7, 0xb2, +0xab, 0xa7, 0xad, 0xab, 0xba, 0xb8, 0xef, 0x6d, 0x34, 0x2f, 0x2d, 0x2a, +0x2c, 0x29, 0x36, 0x34, 0xe9, 0xde, 0xba, 0xb6, 0xac, 0xa8, 0xac, 0xaa, +0xb8, 0xb4, 0xd8, 0xdc, 0x38, 0x33, 0x2e, 0x2b, 0x2c, 0x29, 0x33, 0x30, +0x65, 0x6a, 0xbe, 0xba, 0xad, 0xaa, 0xac, 0xa9, 0xb5, 0xb1, 0xcd, 0xcc, +0x3c, 0x37, 0x2f, 0x2c, 0x2d, 0x29, 0x31, 0x2e, 0x53, 0x54, 0xc2, 0xbe, +0xaf, 0xab, 0xac, 0xa9, 0xb4, 0xaf, 0xc6, 0xc3, 0x41, 0x3c, 0x2f, 0x2d, +0x2d, 0x29, 0x2f, 0x2c, 0x4b, 0x49, 0xc8, 0xc4, 0xb1, 0xad, 0xac, 0xa8, +0xb2, 0xae, 0xc1, 0xbd, 0x49, 0x42, 0x32, 0x2e, 0x2e, 0x2a, 0x2f, 0x2b, +0x44, 0x40, 0xcf, 0xcc, 0xb5, 0xae, 0xac, 0xa8, 0xb1, 0xad, 0xbd, 0xb9, +0x54, 0x4c, 0x35, 0x2f, 0x2e, 0x2a, 0x2e, 0x2a, 0x3e, 0x3b, 0xdc, 0xda, +0xb8, 0xb1, 0xad, 0xa9, 0xb0, 0xac, 0xbb, 0xb6, 0x6c, 0x5d, 0x37, 0x32, +0x2f, 0x2b, 0x2e, 0x29, 0x3b, 0x37, 0xf9, 0xfa, 0xbc, 0xb5, 0xae, 0xa9, +0xaf, 0xab, 0xb9, 0xb2, 0xe4, 0xed, 0x3b, 0x35, 0x31, 0x2c, 0x2e, 0x29, +0x38, 0x33, 0x62, 0x5c, 0xbf, 0xb9, 0xaf, 0xaa, 0xaf, 0xaa, 0xb7, 0xaf, +0xd3, 0xd2, 0x3e, 0x39, 0x33, 0x2c, 0x2e, 0x28, 0x36, 0x2f, 0x55, 0x4d, +0xc6, 0xbd, 0xb0, 0xab, 0xaf, 0xaa, 0xb6, 0xae, 0xca, 0xc6, 0x43, 0x3d, +0x35, 0x2d, 0x2e, 0x28, 0x34, 0x2d, 0x4c, 0x44, 0xcd, 0xc5, 0xb3, 0xac, +0xaf, 0xa9, 0xb4, 0xad, 0xc4, 0xbe, 0x4a, 0x43, 0x37, 0x2f, 0x2f, 0x29, +0x32, 0x2c, 0x47, 0x3e, 0xd7, 0xcd, 0xb6, 0xae, 0xaf, 0xa9, 0xb4, 0xac, +0xbf, 0xba, 0x54, 0x4c, 0x39, 0x30, 0x30, 0x29, 0x31, 0x2a, 0x41, 0x3a, +0xe5, 0xdb, 0xba, 0xb0, 0xaf, 0xa9, 0xb3, 0xab, 0xbc, 0xb5, 0x67, 0x5e, +0x3b, 0x32, 0x32, 0x2a, 0x30, 0x29, 0x3e, 0x35, 0x7a, 0x7b, 0xbe, 0xb5, +0xb0, 0xa9, 0xb3, 0xaa, 0xbb, 0xb2, 0xe9, 0xe2, 0x3d, 0x36, 0x34, 0x2b, +0x30, 0x28, 0x3b, 0x31, 0x60, 0x57, 0xc3, 0xba, 0xb2, 0xaa, 0xb3, 0xa9, +0xb9, 0xaf, 0xd6, 0xcd, 0x41, 0x3a, 0x37, 0x2c, 0x30, 0x28, 0x39, 0x2e, +0x55, 0x4a, 0xca, 0xbf, 0xb4, 0xab, 0xb3, 0xa9, 0xb8, 0xad, 0xcc, 0xc2, +0x47, 0x3e, 0x38, 0x2d, 0x31, 0x28, 0x37, 0x2c, 0x4d, 0x41, 0xd1, 0xc7, +0xb7, 0xad, 0xb3, 0xa9, 0xb7, 0xac, 0xc6, 0xbc, 0x4d, 0x46, 0x3a, 0x2f, +0x32, 0x28, 0x35, 0x2b, 0x48, 0x3b, 0xdd, 0xd4, 0xb9, 0xae, 0xb3, 0xa9, +0xb6, 0xab, 0xc1, 0xb7, 0x56, 0x52, 0x3c, 0x31, 0x33, 0x28, 0x34, 0x29, +0x44, 0x37, 0xef, 0xf4, 0xbc, 0xb1, 0xb4, 0xa9, 0xb6, 0xaa, 0xbe, 0xb2, +0x66, 0x75, 0x3f, 0x35, 0x35, 0x29, 0x34, 0x28, 0x40, 0x32, 0x6b, 0x59, +0xbf, 0xb6, 0xb5, 0xaa, 0xb6, 0xa9, 0xbc, 0xaf, 0xf4, 0xd9, 0x43, 0x3a, +0x37, 0x2b, 0x34, 0x28, 0x3e, 0x2f, 0x5b, 0x4b, 0xc4, 0xbb, 0xb7, 0xab, +0xb6, 0xa9, 0xbb, 0xad, 0xdd, 0xca, 0x47, 0x3e, 0x39, 0x2c, 0x34, 0x27, +0x3c, 0x2d, 0x52, 0x41, 0xca, 0xc0, 0xb8, 0xac, 0xb6, 0xa9, 0xba, 0xab, +0xd2, 0xbf, 0x4c, 0x45, 0x3b, 0x2e, 0x34, 0x27, 0x3b, 0x2c, 0x4c, 0x3b, +0xd0, 0xcc, 0xba, 0xae, 0xb7, 0xa9, 0xb9, 0xaa, 0xcb, 0xb9, 0x53, 0x50, +0x3d, 0x30, 0x35, 0x28, 0x3a, 0x2a, 0x48, 0x37, 0xdb, 0xe0, 0xbc, 0xb0, +0xb7, 0xaa, 0xb8, 0xa9, 0xc7, 0xb5, 0x5c, 0x69, 0x3f, 0x35, 0x36, 0x29, +0x39, 0x29, 0x45, 0x33, 0xec, 0x63, 0xbe, 0xb4, 0xb8, 0xaa, 0xb8, 0xa9, +0xc2, 0xb0, 0x6d, 0xdf, 0x43, 0x39, 0x37, 0x2a, 0x38, 0x28, 0x42, 0x2f, +0x6e, 0x4e, 0xc2, 0xb9, 0xb9, 0xab, 0xb8, 0xa8, 0xbf, 0xae, 0xee, 0xcd, +0x47, 0x3e, 0x39, 0x2b, 0x38, 0x28, 0x3f, 0x2e, 0x5d, 0x42, 0xc7, 0xbe, +0xba, 0xac, 0xb8, 0xa8, 0xbd, 0xac, 0xde, 0xc3, 0x4c, 0x46, 0x3b, 0x2d, +0x38, 0x28, 0x3e, 0x2c, 0x54, 0x3c, 0xcc, 0xc7, 0xbc, 0xae, 0xb9, 0xa9, +0xbc, 0xaa, 0xd5, 0xbc, 0x50, 0x4f, 0x3d, 0x2f, 0x38, 0x28, 0x3d, 0x2c, +0x4e, 0x38, 0xd3, 0xd5, 0xbd, 0xb0, 0xba, 0xaa, 0xbb, 0xa9, 0xce, 0xb8, +0x58, 0x63, 0x3f, 0x34, 0x38, 0x28, 0x3c, 0x2b, 0x4a, 0x34, 0xde, 0x78, +0xbf, 0xb3, 0xbb, 0xab, 0xbb, 0xa9, 0xc9, 0xb3, 0x60, 0xea, 0x44, 0x3a, +0x39, 0x29, 0x3c, 0x2a, 0x47, 0x31, 0xf7, 0x51, 0xc1, 0xb7, 0xbc, 0xad, +0xba, 0xa9, 0xc5, 0xaf, 0x6f, 0xd2, 0x48, 0x3f, 0x3a, 0x2b, 0x3b, 0x2a, +0x45, 0x2f, 0x68, 0x45, 0xc5, 0xbc, 0xbd, 0xae, 0xbb, 0xa9, 0xc2, 0xae, +0xef, 0xc8, 0x4c, 0x49, 0x3b, 0x2c, 0x3b, 0x2a, 0x43, 0x2e, 0x5b, 0x3d, +0xc9, 0xc2, 0xbe, 0xb0, 0xbb, 0xa9, 0xbf, 0xac, 0xe0, 0xc0, 0x50, 0x56, +0x3d, 0x2f, 0x3b, 0x2a, 0x41, 0x2d, 0x53, 0x39, 0xce, 0xcc, 0xbf, 0xb3, +0xbb, 0xaa, 0xbe, 0xab, 0xd8, 0xbb, 0x58, 0x72, 0x3f, 0x32, 0x3b, 0x2a, +0x40, 0x2c, 0x4e, 0x35, 0xd5, 0xdc, 0xc1, 0xb7, 0xbc, 0xab, 0xbd, 0xaa, +0xd1, 0xb8, 0x60, 0xdc, 0x42, 0x36, 0x3b, 0x2b, 0x3f, 0x2c, 0x4b, 0x31, +0xdf, 0x6c, 0xc4, 0xba, 0xbd, 0xad, 0xbd, 0xaa, 0xcd, 0xb4, 0x6e, 0xce, +0x46, 0x3b, 0x3c, 0x2c, 0x3e, 0x2c, 0x48, 0x2f, 0xf2, 0x53, 0xc7, 0xbe, +0xbe, 0xae, 0xbd, 0xaa, 0xc9, 0xb2, 0xf5, 0xc5, 0x4a, 0x41, 0x3d, 0x2d, +0x3e, 0x2c, 0x45, 0x2e, 0x6d, 0x48, 0xcb, 0xc5, 0xbf, 0xb0, 0xbc, 0xaa, +0xc6, 0xaf, 0xe4, 0xbf, 0x4f, 0x4b, 0x3e, 0x2f, 0x3e, 0x2c, 0x44, 0x2d, +0x5e, 0x3f, 0xce, 0xcd, 0xc1, 0xb3, 0xbd, 0xaa, 0xc4, 0xae, 0xdb, 0xbb, +0x55, 0x5a, 0x40, 0x32, 0x3e, 0x2c, 0x42, 0x2c, 0x56, 0x3a, 0xd4, 0xdb, +0xc4, 0xb7, 0xbd, 0xab, 0xc2, 0xad, 0xd5, 0xb8, 0x5d, 0xf5, 0x43, 0x35, +0x3e, 0x2d, 0x41, 0x2c, 0x50, 0x37, 0xdc, 0xff, 0xc7, 0xbb, 0xbe, 0xac, +0xc1, 0xac, 0xd0, 0xb5, 0x69, 0xd6, 0x46, 0x39, 0x3f, 0x2e, 0x40, 0x2c, +0x4d, 0x33, 0xe6, 0x5b, 0xca, 0xbf, 0xbf, 0xad, 0xbf, 0xac, 0xcd, 0xb3, +0x7e, 0xca, 0x49, 0x3d, 0x3f, 0x2f, 0x40, 0x2b, 0x4a, 0x30, 0xfb, 0x4d, +0xcd, 0xc6, 0xc0, 0xae, 0xbf, 0xab, 0xcb, 0xb0, 0xe9, 0xc1, 0x4d, 0x44, +0x41, 0x30, 0x40, 0x2c, 0x47, 0x2e, 0x6b, 0x45, 0xd0, 0xcd, 0xc3, 0xb1, +0xbf, 0xab, 0xc9, 0xaf, 0xde, 0xbc, 0x52, 0x4f, 0x42, 0x32, 0x41, 0x2c, +0x45, 0x2d, 0x5e, 0x3e, 0xd5, 0xd9, 0xc6, 0xb5, 0xbf, 0xab, 0xc7, 0xae, +0xd9, 0xb9, 0x5a, 0x63, 0x44, 0x34, 0x42, 0x2d, 0x44, 0x2c, 0x57, 0x3a, +0xda, 0xef, 0xc9, 0xb9, 0xbf, 0xab, 0xc5, 0xad, 0xd5, 0xb6, 0x65, 0xe1, +0x46, 0x37, 0x42, 0x2e, 0x43, 0x2b, 0x51, 0x35, 0xe0, 0x64, 0xcc, 0xbe, +0xc0, 0xac, 0xc4, 0xad, 0xd1, 0xb3, 0x79, 0xce, 0x49, 0x3b, 0x43, 0x2f, +0x43, 0x2b, 0x4d, 0x31, 0xeb, 0x52, 0xce, 0xc4, 0xc2, 0xad, 0xc3, 0xac, +0xce, 0xb1, 0xee, 0xc5, 0x4c, 0x3f, 0x44, 0x30, 0x43, 0x2b, 0x4b, 0x2f, +0x7e, 0x49, 0xd2, 0xcc, 0xc3, 0xaf, 0xc2, 0xac, 0xcc, 0xaf, 0xe1, 0xbe, +0x4f, 0x46, 0x46, 0x32, 0x43, 0x2b, 0x49, 0x2d, 0x6c, 0x40, 0xd8, 0xd8, +0xc6, 0xb1, 0xc2, 0xab, 0xcb, 0xae, 0xdb, 0xb9, 0x55, 0x51, 0x47, 0x35, +0x44, 0x2c, 0x47, 0x2c, 0x5f, 0x3b, 0xdd, 0xf6, 0xc8, 0xb5, 0xc2, 0xab, +0xc9, 0xad, 0xd6, 0xb5, 0x5c, 0x6b, 0x49, 0x38, 0x45, 0x2c, 0x46, 0x2b, +0x5a, 0x37, 0xe5, 0x5c, 0xcb, 0xb9, 0xc3, 0xac, 0xc8, 0xac, 0xd2, 0xb1, +0x66, 0xdd, 0x4b, 0x3b, 0x45, 0x2d, 0x45, 0x2a, 0x55, 0x33, 0xee, 0x4e, +0xcd, 0xbd, 0xc3, 0xac, 0xc7, 0xab, 0xcf, 0xaf, 0x75, 0xcc, 0x4d, 0x3e, +0x47, 0x2e, 0x44, 0x2a, 0x50, 0x30, 0x7e, 0x46, 0xd1, 0xc3, 0xc5, 0xad, +0xc7, 0xab, 0xcd, 0xad, 0xf1, 0xc3, 0x50, 0x44, 0x48, 0x2f, 0x44, 0x29, +0x4e, 0x2e, 0x6d, 0x3e, 0xd6, 0xcc, 0xc6, 0xae, 0xc7, 0xab, 0xcc, 0xac, +0xe5, 0xbc, 0x54, 0x4d, 0x4a, 0x32, 0x44, 0x29, 0x4c, 0x2c, 0x64, 0x3a, +0xdc, 0xdd, 0xc8, 0xb0, 0xc6, 0xab, 0xcb, 0xab, 0xdd, 0xb7, 0x59, 0x5c, +0x4b, 0x35, 0x45, 0x2a, 0x4a, 0x2b, 0x5d, 0x36, 0xe2, 0x6d, 0xca, 0xb4, +0xc7, 0xab, 0xca, 0xaa, 0xd8, 0xb3, 0x5e, 0xf4, 0x4d, 0x39, 0x46, 0x2a, +0x49, 0x2a, 0x59, 0x33, 0xed, 0x51, 0xcc, 0xb7, 0xc7, 0xac, 0xc9, 0xa9, +0xd3, 0xaf, 0x67, 0xd6, 0x4f, 0x3c, 0x47, 0x2b, 0x48, 0x29, 0x56, 0x2f, +0xfb, 0x47, 0xce, 0xbc, 0xc8, 0xac, 0xc9, 0xa9, 0xd0, 0xad, 0x73, 0xc8, +0x52, 0x41, 0x48, 0x2c, 0x47, 0x28, 0x53, 0x2e, 0x72, 0x3e, 0xd2, 0xc2, +0xc8, 0xad, 0xc9, 0xa9, 0xce, 0xab, 0xf9, 0xbf, 0x55, 0x49, 0x4a, 0x2e, +0x47, 0x27, 0x50, 0x2c, 0x69, 0x3a, 0xd7, 0xce, 0xc9, 0xae, 0xc9, 0xa9, +0xcd, 0xaa, 0xe9, 0xba, 0x58, 0x51, 0x4c, 0x31, 0x47, 0x27, 0x4e, 0x2b, +0x62, 0x36, 0xdd, 0xe5, 0xca, 0xaf, 0xc9, 0xaa, 0xcc, 0xa9, 0xdf, 0xb5, +0x5c, 0x60, 0x4e, 0x35, 0x47, 0x28, 0x4d, 0x29, 0x5d, 0x33, 0xe4, 0x5f, +0xcb, 0xb2, 0xca, 0xaa, 0xcb, 0xa8, 0xdb, 0xb0, 0x5f, 0xec, 0x4f, 0x39, +0x47, 0x28, 0x4c, 0x28, 0x5b, 0x2f, 0xee, 0x4d, 0xcd, 0xb5, 0xca, 0xab, +0xcb, 0xa7, 0xd6, 0xad, 0x67, 0xd3, 0x52, 0x3d, 0x48, 0x29, 0x4b, 0x28, +0x58, 0x2e, 0xff, 0x42, 0xcf, 0xba, 0xcb, 0xac, 0xca, 0xa7, 0xd3, 0xac, +0x6f, 0xc8, 0x56, 0x43, 0x49, 0x2a, 0x4a, 0x27, 0x55, 0x2c, 0x6f, 0x3c, +0xd2, 0xbe, 0xcb, 0xad, 0xca, 0xa7, 0xd0, 0xaa, 0xfe, 0xc0, 0x59, 0x4b, +0x4b, 0x2c, 0x4a, 0x27, 0x52, 0x2b, 0x67, 0x38, 0xd7, 0xc6, 0xcc, 0xae, +0xca, 0xa7, 0xce, 0xa8, 0xee, 0xbb, 0x5d, 0x57, 0x4c, 0x2e, 0x49, 0x27, +0x50, 0x2a, 0x60, 0x33, 0xdb, 0xd2, 0xcd, 0xaf, 0xcb, 0xa8, 0xcd, 0xa7, +0xe6, 0xb6, 0x61, 0x76, 0x4e, 0x30, 0x4a, 0x27, 0x4f, 0x29, 0x5d, 0x2f, +0xe0, 0xf0, 0xce, 0xb2, 0xcb, 0xa9, 0xcc, 0xa6, 0xdf, 0xb2, 0x68, 0xdd, +0x50, 0x35, 0x4a, 0x27, 0x4e, 0x28, 0x5a, 0x2e, 0xe8, 0x5a, 0xd0, 0xb5, +0xcc, 0xaa, 0xcc, 0xa5, 0xdc, 0xaf, 0x6e, 0xce, 0x53, 0x39, 0x4a, 0x28, +0x4e, 0x28, 0x57, 0x2c, 0xf3, 0x4a, 0xd3, 0xb9, 0xcd, 0xab, 0xcb, 0xa5, +0xd9, 0xad, 0x7b, 0xc5, 0x57, 0x3e, 0x4b, 0x29, 0x4d, 0x27, 0x55, 0x2a, +0x7c, 0x40, 0xd6, 0xbd, 0xce, 0xac, 0xcb, 0xa4, 0xd6, 0xab, 0xf8, 0xbe, +0x5a, 0x46, 0x4c, 0x2a, 0x4d, 0x27, 0x53, 0x29, 0x6e, 0x3a, 0xd9, 0xc2, +0xcf, 0xad, 0xcb, 0xa4, 0xd3, 0xa9, 0xed, 0xba, 0x5e, 0x4f, 0x4d, 0x2b, +0x4d, 0x27, 0x51, 0x28, 0x67, 0x36, 0xdc, 0xca, 0xd0, 0xaf, 0xcc, 0xa4, +0xd1, 0xa8, 0xe8, 0xb6, 0x63, 0x63, 0x4e, 0x2c, 0x4d, 0x27, 0x50, 0x27, +0x60, 0x31, 0xdf, 0xd4, 0xd2, 0xb0, 0xcc, 0xa5, 0xcf, 0xa6, 0xe3, 0xb2, +0x6a, 0xe8, 0x51, 0x2e, 0x4d, 0x27, 0x50, 0x26, 0x5d, 0x2e, 0xe6, 0xef, +0xd4, 0xb3, 0xcd, 0xa6, 0xce, 0xa4, 0xde, 0xaf, 0x71, 0xd0, 0x54, 0x31, +0x4d, 0x26, 0x50, 0x26, 0x5a, 0x2b, 0xed, 0x5d, 0xd6, 0xb6, 0xce, 0xa7, +0xce, 0xa3, 0xdd, 0xae, 0x7b, 0xc8, 0x57, 0x36, 0x4e, 0x27, 0x50, 0x26, +0x58, 0x2a, 0xf9, 0x4b, 0xd8, 0xb9, 0xcf, 0xa8, 0xce, 0xa2, 0xda, 0xac, +0xfa, 0xc1, 0x5b, 0x3b, 0x4e, 0x27, 0x50, 0x25, 0x57, 0x28, 0x77, 0x41, +0xdb, 0xbc, 0xd1, 0xaa, 0xce, 0xa2, 0xd8, 0xaa, 0xf1, 0xbc, 0x5e, 0x3f, +0x4f, 0x28, 0x50, 0x25, 0x55, 0x26, 0x6d, 0x3b, 0xdd, 0xc0, 0xd3, 0xab, +0xce, 0xa1, 0xd6, 0xa8, 0xeb, 0xb7, 0x63, 0x49, 0x50, 0x29, 0x50, 0x24, +0x54, 0x25, 0x67, 0x36, 0xe0, 0xc8, 0xd5, 0xac, 0xce, 0xa2, 0xd5, 0xa6, +0xe7, 0xb3, 0x69, 0x56, 0x53, 0x2b, 0x50, 0x24, 0x54, 0x24, 0x62, 0x31, +0xe6, 0xd3, 0xd7, 0xae, 0xcf, 0xa2, 0xd3, 0xa5, 0xe3, 0xaf, 0x6f, 0x7c, +0x55, 0x2c, 0x51, 0x25, 0x53, 0x23, 0x5e, 0x2e, 0xeb, 0xe9, 0xd9, 0xb0, +0xd0, 0xa3, 0xd3, 0xa3, 0xdf, 0xad, 0x79, 0xd6, 0x58, 0x2e, 0x52, 0x25, +0x53, 0x22, 0x5c, 0x2b, 0xf3, 0x5e, 0xdb, 0xb4, 0xd1, 0xa3, 0xd2, 0xa2, +0xde, 0xab, 0xfd, 0xc8, 0x5b, 0x31, 0x52, 0x26, 0x53, 0x22, 0x5b, 0x29, +0xfd, 0x4c, 0xde, 0xb9, 0xd3, 0xa5, 0xd2, 0xa1, 0xdc, 0xa9, 0xf4, 0xbd, +0x5d, 0x36, 0x54, 0x27, 0x53, 0x22, 0x59, 0x26, 0x79, 0x41, 0xe0, 0xbd, +0xd5, 0xa6, 0xd2, 0xa0, 0xdb, 0xa8, 0xed, 0xb8, 0x60, 0x3c, 0x55, 0x27, +0x54, 0x21, 0x58, 0x24, 0x6f, 0x3a, 0xe4, 0xc4, 0xd7, 0xa8, 0xd2, 0xa0, +0xda, 0xa6, 0xe9, 0xb3, 0x65, 0x43, 0x57, 0x29, 0x54, 0x21, 0x57, 0x22, +0x6b, 0x35, 0xe8, 0xcd, 0xd9, 0xaa, 0xd2, 0xa0, 0xd9, 0xa4, 0xe6, 0xaf, +0x6a, 0x4f, 0x58, 0x2a, 0x55, 0x22, 0x57, 0x21, 0x67, 0x2f, 0xec, 0xe0, +0xda, 0xac, 0xd3, 0xa0, 0xd8, 0xa3, 0xe4, 0xac, 0x6e, 0x6a, 0x59, 0x2c, +0x55, 0x22, 0x56, 0x20, 0x63, 0x2d, 0xef, 0x64, 0xdc, 0xae, 0xd4, 0xa0, +0xd7, 0xa1, 0xe1, 0xaa, 0x77, 0xd8, 0x5b, 0x2e, 0x56, 0x23, 0x56, 0x1f, +0x60, 0x2a, 0xf6, 0x4e, 0xde, 0xb2, 0xd5, 0xa1, 0xd7, 0xa0, 0xdf, 0xa8, +0xff, 0xc6, 0x5d, 0x31, 0x57, 0x24, 0x56, 0x1f, 0x5e, 0x27, 0xfd, 0x44, +0xdf, 0xb7, 0xd6, 0xa3, 0xd6, 0x9f, 0xde, 0xa6, 0xf9, 0xbc, 0x5f, 0x36, +0x57, 0x25, 0x57, 0x1f, 0x5d, 0x25, 0x7b, 0x3c, 0xe2, 0xbc, 0xd8, 0xa4, +0xd6, 0x9f, 0xdd, 0xa5, 0xf1, 0xb7, 0x62, 0x3b, 0x58, 0x26, 0x57, 0x1f, +0x5b, 0x22, 0x74, 0x37, 0xe5, 0xc2, 0xd9, 0xa6, 0xd6, 0x9f, 0xdd, 0xa3, +0xed, 0xb1, 0x66, 0x43, 0x59, 0x27, 0x57, 0x1f, 0x5a, 0x20, 0x6d, 0x31, +0xe8, 0xcc, 0xda, 0xa8, 0xd5, 0x9e, 0xdc, 0xa1, 0xeb, 0xae, 0x6a, 0x4f, +0x59, 0x29, 0x57, 0x1f, 0x5a, 0x1f, 0x6a, 0x2d, 0xeb, 0xe2, 0xdc, 0xaa, +0xd6, 0x9f, 0xdb, 0xa0, 0xe8, 0xab, 0x6e, 0x74, 0x5b, 0x2b, 0x58, 0x20, +0x59, 0x1f, 0x67, 0x2b, 0xee, 0x60, 0xdd, 0xad, 0xd6, 0x9f, 0xda, 0x9f, +0xe6, 0xa9, 0x74, 0xd6, 0x5c, 0x2e, 0x58, 0x21, 0x59, 0x1f, 0x63, 0x29, +0xf3, 0x4d, 0xde, 0xb0, 0xd7, 0xa0, 0xd9, 0x9f, 0xe3, 0xa7, 0x7b, 0xc7, +0x5e, 0x31, 0x58, 0x22, 0x58, 0x1e, 0x60, 0x26, 0xfa, 0x41, 0xe0, 0xb5, +0xd7, 0xa2, 0xd8, 0x9f, 0xe1, 0xa5, 0xfc, 0xbd, 0x5f, 0x36, 0x59, 0x24, +0x58, 0x1e, 0x5f, 0x24, 0x7e, 0x3b, 0xe3, 0xbc, 0xd8, 0xa4, 0xd8, 0x9f, +0xdf, 0xa3, 0xf5, 0xb6, 0x62, 0x3d, 0x5a, 0x26, 0x58, 0x1f, 0x5d, 0x22, +0x77, 0x35, 0xe6, 0xc5, 0xd9, 0xa6, 0xd7, 0x9f, 0xde, 0xa2, 0xef, 0xb0, +0x65, 0x46, 0x5a, 0x28, 0x58, 0x1f, 0x5c, 0x21, 0x6f, 0x30, 0xe9, 0xd2, +0xda, 0xa8, 0xd7, 0x9f, 0xdc, 0xa1, 0xeb, 0xad, 0x69, 0x53, 0x5b, 0x2a, +0x58, 0x1f, 0x5b, 0x1f, 0x6c, 0x2d, 0xed, 0xf3, 0xdc, 0xab, 0xd7, 0x9f, +0xdb, 0xa0, 0xe8, 0xab, 0x6d, 0x7e, 0x5c, 0x2c, 0x58, 0x20, 0x5a, 0x1f, +0x68, 0x2b, 0xf1, 0x58, 0xdd, 0xad, 0xd7, 0xa0, 0xda, 0x9f, 0xe4, 0xa9, +0x73, 0xd3, 0x5d, 0x2f, 0x58, 0x21, 0x59, 0x1f, 0x64, 0x28, 0xf8, 0x49, +0xde, 0xb1, 0xd7, 0xa1, 0xd9, 0x9f, 0xe1, 0xa7, 0x7b, 0xc5, 0x5f, 0x33, +0x58, 0x23, 0x58, 0x1f, 0x60, 0x27, 0xff, 0x3f, 0xe1, 0xb7, 0xd8, 0xa3, +0xd8, 0x9f, 0xdf, 0xa5, 0xfa, 0xbc, 0x60, 0x38, 0x59, 0x25, 0x57, 0x1f, +0x5e, 0x24, 0x79, 0x3a, 0xe4, 0xbd, 0xd8, 0xa5, 0xd7, 0x9f, 0xdd, 0xa4, +0xf1, 0xb6, 0x64, 0x3e, 0x59, 0x27, 0x57, 0x1f, 0x5c, 0x23, 0x71, 0x35, +0xe8, 0xc7, 0xd9, 0xa7, 0xd6, 0x9f, 0xdc, 0xa3, 0xeb, 0xb0, 0x67, 0x47, +0x5a, 0x29, 0x56, 0x1f, 0x5a, 0x21, 0x6c, 0x30, 0xeb, 0xd6, 0xda, 0xa9, +0xd5, 0x9f, 0xda, 0xa2, 0xe6, 0xad, 0x6b, 0x57, 0x5b, 0x2b, 0x56, 0x20, +0x58, 0x1f, 0x67, 0x2e, 0xef, 0xff, 0xdc, 0xac, 0xd5, 0x9f, 0xd9, 0xa1, +0xe2, 0xab, 0x72, 0xf4, 0x5b, 0x2d, 0x56, 0x22, 0x56, 0x1f, 0x62, 0x2b, +0xf7, 0x56, 0xdd, 0xaf, 0xd4, 0xa0, 0xd7, 0xa1, 0xde, 0xa9, 0x7c, 0xd0, +0x5d, 0x2f, 0x56, 0x23, 0x55, 0x1f, 0x5e, 0x29, 0xff, 0x48, 0xdf, 0xb4, +0xd4, 0xa2, 0xd6, 0xa0, 0xdc, 0xa7, 0xf7, 0xc3, 0x5e, 0x34, 0x57, 0x25, +0x53, 0x1f, 0x5b, 0x27, 0x76, 0x3f, 0xe2, 0xb9, 0xd5, 0xa4, 0xd4, 0xa1, +0xda, 0xa5, 0xed, 0xbc, 0x60, 0x39, 0x57, 0x27, 0x52, 0x1f, 0x59, 0x26, +0x6e, 0x3a, 0xe6, 0xbf, 0xd5, 0xa5, 0xd2, 0xa1, 0xd8, 0xa5, 0xe8, 0xb7, +0x63, 0x3e, 0x57, 0x29, 0x51, 0x1f, 0x56, 0x25, 0x68, 0x36, 0xea, 0xca, +0xd5, 0xa8, 0xd1, 0xa2, 0xd5, 0xa4, 0xe1, 0xb2, 0x68, 0x49, 0x58, 0x2b, +0x50, 0x20, 0x53, 0x23, 0x62, 0x32, 0xef, 0xdc, 0xd7, 0xaa, 0xd0, 0xa2, +0xd3, 0xa3, 0xdd, 0xae, 0x6d, 0x59, 0x59, 0x2e, 0x4f, 0x22, 0x51, 0x23, +0x5e, 0x2e, 0xfa, 0x66, 0xd8, 0xad, 0xcf, 0xa4, 0xd1, 0xa3, 0xda, 0xac, +0x77, 0xee, 0x5a, 0x31, 0x4f, 0x24, 0x4f, 0x22, 0x5b, 0x2d, 0x7a, 0x4e, +0xd9, 0xb0, 0xcf, 0xa5, 0xcf, 0xa3, 0xd7, 0xaa, 0xfb, 0xd2, 0x5b, 0x36, +0x4f, 0x25, 0x4e, 0x22, 0x57, 0x2b, 0x6e, 0x44, 0xdb, 0xb5, 0xcf, 0xa6, +0xce, 0xa3, 0xd3, 0xa9, 0xee, 0xc7, 0x5d, 0x3a, 0x4f, 0x27, 0x4c, 0x22, +0x54, 0x2a, 0x68, 0x3d, 0xde, 0xbb, 0xcf, 0xa8, 0xcd, 0xa4, 0xd0, 0xa7, +0xe7, 0xbe, 0x5f, 0x3f, 0x4f, 0x29, 0x4b, 0x22, 0x50, 0x29, 0x61, 0x39, +0xe2, 0xc3, 0xcf, 0xaa, 0xcc, 0xa4, 0xce, 0xa6, 0xdf, 0xb9, 0x64, 0x49, +0x50, 0x2c, 0x4a, 0x23, 0x4e, 0x28, 0x5d, 0x35, 0xe8, 0xcf, 0xcf, 0xac, +0xcb, 0xa5, 0xcc, 0xa6, 0xdb, 0xb4, 0x69, 0x55, 0x52, 0x2e, 0x4a, 0x24, +0x4c, 0x27, 0x59, 0x31, 0xf1, 0xe9, 0xd0, 0xad, 0xcb, 0xa6, 0xcb, 0xa5, +0xd6, 0xb0, 0x6f, 0x6c, 0x53, 0x31, 0x4a, 0x25, 0x4b, 0x26, 0x55, 0x2f, +0x7e, 0x5d, 0xd1, 0xb0, 0xca, 0xa7, 0xca, 0xa5, 0xd2, 0xae, 0x7c, 0xdf, +0x55, 0x36, 0x49, 0x27, 0x49, 0x25, 0x52, 0x2e, 0x6e, 0x4c, 0xd4, 0xb4, +0xca, 0xa8, 0xc9, 0xa6, 0xce, 0xac, 0xf3, 0xcf, 0x57, 0x3a, 0x4a, 0x29, +0x47, 0x25, 0x4f, 0x2d, 0x66, 0x43, 0xd7, 0xba, 0xc9, 0xaa, 0xc8, 0xa7, +0xcc, 0xab, 0xe8, 0xc7, 0x5a, 0x3e, 0x4a, 0x2b, 0x45, 0x25, 0x4d, 0x2c, +0x5e, 0x3e, 0xdb, 0xbf, 0xc9, 0xab, 0xc7, 0xa7, 0xca, 0xaa, 0xdf, 0xbf, +0x5c, 0x46, 0x4b, 0x2d, 0x45, 0x26, 0x4b, 0x2b, 0x5a, 0x3a, 0xdf, 0xc7, +0xca, 0xad, 0xc7, 0xa8, 0xc8, 0xa9, 0xda, 0xbc, 0x60, 0x4e, 0x4c, 0x2f, +0x44, 0x27, 0x49, 0x2b, 0x56, 0x37, 0xe7, 0xd3, 0xca, 0xaf, 0xc6, 0xa9, +0xc6, 0xa9, 0xd5, 0xb8, 0x67, 0x5d, 0x4d, 0x32, 0x43, 0x28, 0x47, 0x2b, +0x51, 0x34, 0xf3, 0xeb, 0xcb, 0xb2, 0xc6, 0xab, 0xc5, 0xa9, 0xcf, 0xb5, +0x6f, 0xfa, 0x4f, 0x37, 0x43, 0x29, 0x45, 0x2b, 0x4e, 0x32, 0x79, 0x60, +0xcd, 0xb6, 0xc6, 0xac, 0xc3, 0xa9, 0xcd, 0xb2, 0xfd, 0xdb, 0x51, 0x3b, +0x43, 0x2b, 0x44, 0x2a, 0x4c, 0x30, 0x69, 0x4f, 0xce, 0xba, 0xc6, 0xad, +0xc2, 0xa9, 0xca, 0xb0, 0xed, 0xce, 0x54, 0x3f, 0x44, 0x2c, 0x42, 0x2a, +0x4a, 0x2f, 0x5f, 0x47, 0xd1, 0xbe, 0xc6, 0xae, 0xc1, 0xaa, 0xc8, 0xae, +0xe3, 0xc8, 0x58, 0x46, 0x44, 0x2d, 0x41, 0x2b, 0x48, 0x2e, 0x59, 0x40, +0xd5, 0xc3, 0xc6, 0xaf, 0xc1, 0xaa, 0xc5, 0xae, 0xdc, 0xc2, 0x5d, 0x4d, +0x46, 0x2f, 0x40, 0x2b, 0x46, 0x2e, 0x54, 0x3d, 0xda, 0xcb, 0xc7, 0xb2, +0xc1, 0xab, 0xc3, 0xad, 0xd7, 0xbe, 0x64, 0x58, 0x47, 0x32, 0x3f, 0x2b, +0x45, 0x2e, 0x4f, 0x3a, 0xdf, 0xd5, 0xc9, 0xb5, 0xc1, 0xac, 0xc1, 0xad, +0xd1, 0xbc, 0x6e, 0x6c, 0x49, 0x36, 0x3f, 0x2c, 0x43, 0x2e, 0x4c, 0x37, +0xeb, 0xe9, 0xca, 0xb8, 0xc1, 0xad, 0xbf, 0xac, 0xce, 0xb9, 0xfe, 0xe8, +0x4b, 0x39, 0x3f, 0x2d, 0x42, 0x2d, 0x4a, 0x36, 0x7f, 0x68, 0xcc, 0xbb, +0xc2, 0xae, 0xbf, 0xac, 0xcb, 0xb7, 0xec, 0xd8, 0x4e, 0x3d, 0x3f, 0x2e, +0x41, 0x2e, 0x47, 0x34, 0x69, 0x56, 0xce, 0xbe, 0xc3, 0xaf, 0xbe, 0xac, +0xc8, 0xb5, 0xe3, 0xcf, 0x52, 0x42, 0x40, 0x2f, 0x3f, 0x2e, 0x46, 0x33, +0x5d, 0x4b, 0xd0, 0xc1, 0xc4, 0xb2, 0xbe, 0xad, 0xc5, 0xb3, 0xdd, 0xca, +0x58, 0x49, 0x42, 0x31, 0x3f, 0x2e, 0x44, 0x32, 0x56, 0x45, 0xd5, 0xc8, +0xc5, 0xb4, 0xbe, 0xae, 0xc2, 0xb1, 0xd8, 0xc6, 0x5e, 0x51, 0x43, 0x34, +0x3e, 0x2e, 0x43, 0x32, 0x4f, 0x3f, 0xda, 0xce, 0xc7, 0xb7, 0xbf, 0xaf, +0xc0, 0xb0, 0xd3, 0xc2, 0x68, 0x5d, 0x46, 0x37, 0x3e, 0x2f, 0x42, 0x32, +0x4c, 0x3d, 0xe1, 0xda, 0xc8, 0xb9, 0xbf, 0xaf, 0xbf, 0xaf, 0xcf, 0xbe, +0x78, 0x76, 0x48, 0x3a, 0x3e, 0x2f, 0x41, 0x31, 0x49, 0x3b, 0xee, 0xef, +0xca, 0xbc, 0xbf, 0xb1, 0xbe, 0xaf, 0xcc, 0xbc, 0xee, 0xe4, 0x4b, 0x3d, +0x3e, 0x30, 0x40, 0x31, 0x46, 0x39, 0x76, 0x66, 0xcc, 0xbf, 0xc1, 0xb3, +0xbd, 0xaf, 0xc9, 0xba, 0xe3, 0xd7, 0x4e, 0x42, 0x3f, 0x32, 0x3f, 0x31, +0x44, 0x37, 0x64, 0x56, 0xce, 0xc3, 0xc2, 0xb5, 0xbd, 0xaf, 0xc6, 0xb9, +0xdb, 0xcf, 0x53, 0x48, 0x3f, 0x34, 0x3f, 0x32, 0x42, 0x36, 0x5a, 0x4d, +0xd3, 0xc9, 0xc4, 0xb7, 0xbd, 0xb0, 0xc4, 0xb7, 0xd5, 0xca, 0x5a, 0x4e, +0x41, 0x36, 0x3f, 0x32, 0x40, 0x36, 0x53, 0x48, 0xd8, 0xce, 0xc6, 0xba, +0xbd, 0xb1, 0xc2, 0xb7, 0xd1, 0xc7, 0x64, 0x59, 0x43, 0x39, 0x3f, 0x34, +0x40, 0x36, 0x4e, 0x44, 0xdf, 0xd8, 0xc9, 0xbd, 0xbe, 0xb4, 0xc1, 0xb7, +0xce, 0xc5, 0x75, 0x6b, 0x47, 0x3d, 0x41, 0x37, 0x41, 0x38, 0x4c, 0x42, +0xeb, 0xe6, 0xcd, 0xc2, 0xbf, 0xb7, 0xc1, 0xb8, 0xcd, 0xc4, 0xef, 0xf2, +0x4a, 0x41, 0x43, 0x39, 0x42, 0x39, 0x4a, 0x41, 0xfb, 0xfe, 0xd0, 0xc7, +0xc2, 0xba, 0xc2, 0xba, 0xcc, 0xc4, 0xe4, 0xe2, 0x4e, 0x47, 0x45, 0x3c, +0x43, 0x3b, 0x49, 0x41, 0x6e, 0x69, 0xd7, 0xcc, 0xc5, 0xbd, 0xc3, 0xbb, +0xcc, 0xc4, 0xdd, 0xdb, 0x53, 0x4d, 0x48, 0x3f, 0x45, 0x3d, 0x48, 0x41, +0x65, 0x5e, 0xdd, 0xd2, 0xc9, 0xc0, 0xc4, 0xbd, 0xcc, 0xc4, 0xd9, 0xd6, +0x5a, 0x54, 0x4b, 0x43, 0x47, 0x3f, 0x48, 0x42, 0x5e, 0x59, 0xe4, 0xdb, +0xcc, 0xc6, 0xc6, 0xbf, 0xcc, 0xc6, 0xd6, 0xd4, 0x62, 0x5d, 0x4d, 0x47, +0x49, 0x42, 0x49, 0x44, 0x5b, 0x56, 0xec, 0xe2, 0xcf, 0xca, 0xc8, 0xc2, +0xcc, 0xc7, 0xd5, 0xd2, 0x6e, 0x69, 0x4f, 0x4b, 0x4c, 0x46, 0x4a, 0x46, +0x58, 0x54, 0xf5, 0xec, 0xd6, 0xcf, 0xca, 0xc6, 0xcd, 0xc9, 0xd5, 0xd3, +0xfc, 0x7a, 0x54, 0x4f, 0x4e, 0x4a, 0x4c, 0x49, 0x56, 0x53, 0x7f, 0xfa, +0xdb, 0xd5, 0xcd, 0xca, 0xce, 0xcb, 0xd6, 0xd4, 0xed, 0xf3, 0x59, 0x55, +0x50, 0x4d, 0x4e, 0x4c, 0x55, 0x53, 0x74, 0x78, 0xe0, 0xdc, 0xcf, 0xcd, +0xcf, 0xcd, 0xd7, 0xd6, 0xe8, 0xec, 0x5e, 0x5b, 0x54, 0x50, 0x50, 0x4e, +0x55, 0x55, 0x6d, 0x6f, 0xe8, 0xe1, 0xd5, 0xd3, 0xd2, 0xd1, 0xd9, 0xd9, +0xe5, 0xe9, 0x67, 0x63, 0x5a, 0x58, 0x57, 0x55, 0x59, 0x5a, 0x6c, 0x6e, +0xf0, 0xeb, 0xdd, 0xdc, 0xd9, 0xd9, 0xdd, 0xde, 0xe7, 0xeb, 0x6f, 0x6d, +0x61, 0x5f, 0x5d, 0x5d, 0x5e, 0x5f, 0x6d, 0x6f, 0xfa, 0xf4, 0xe6, 0xe4, +0xdf, 0xdf, 0xe4, 0xe5, 0xeb, 0xee, 0x7a, 0x76, 0x6a, 0x69, 0x66, 0x66, +0x65, 0x67, 0x6f, 0x72, 0xff, 0xfc, 0xee, 0xed, 0xe9, 0xea, 0xeb, 0xec, +0xef, 0xf3, 0x7f, 0x7d, 0x72, 0x71, 0x6e, 0x6e, 0x6d, 0x6f, 0x75, 0x77, +0x7e, 0xff, 0xf8, 0xf7, 0xf1, 0xf3, 0xf3, 0xf5, 0xf7, 0xf9, 0xfe, 0x7f, +0x7a, 0x7a, 0x78, 0x78, 0x77, 0x78, 0x7a, 0x7c, 0x7e, 0x7f, 0xfd, 0xfd, +0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfd, 0xff, 0xff, 0x7e, 0x7e, 0x7e, 0x7e, +0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xee, 0xf3, 0xf9, 0xfd, 0x7b, 0x7b, 0x79, 0x7a, 0x7b, 0x7c, }; +int beepLoLength = 10806 ; +unsigned char beepLo[] = { +0x2e, 0x73, 0x6e, 0x64, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, 0x2a, 0x1a, +0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1f, 0x40, 0x0, 0x0, 0x0, 0x2, +0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0xff, 0x7e, 0xff, 0xfc, 0xff, +0xff, 0x7f, 0xff, 0x7e, 0x7e, 0x7d, 0x7c, 0x7c, 0x7a, 0x7b, 0x7a, 0x7b, +0x7a, 0x7d, 0x7c, 0xff, 0x7f, 0xfe, 0xff, 0xfb, 0xfc, 0xf9, 0xfb, 0xf8, +0xf9, 0xf5, 0xf9, 0xf5, 0xf9, 0xf5, 0xf9, 0xf7, 0xfb, 0xf9, 0xfc, 0xfb, +0xfe, 0xfe, 0x7e, 0x7f, 0x7c, 0x7e, 0x7c, 0x7d, 0x7c, 0x7c, 0x79, 0x7a, +0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0xff, 0xff, 0xfd, 0xfe, 0xfc, 0xfc, +0xfa, 0xfc, 0xf9, 0xfc, 0xf9, 0xfc, 0xf9, 0xfe, 0xfa, 0xfe, 0xfc, 0xfe, +0xfd, 0xfe, 0xff, 0x7f, 0x7e, 0x7e, 0x7c, 0x7e, 0x7c, 0x7e, 0x7c, 0x7e, +0x7c, 0x7e, 0x7e, 0xff, 0x7f, 0xff, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, +0xfd, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x7e, 0xff, 0x7c, 0x7f, 0x7b, 0x7e, +0x7a, 0x7e, 0x79, 0x7b, 0x77, 0x79, 0x75, 0x76, 0x75, 0x76, 0x76, 0x76, +0x76, 0x76, 0x77, 0x77, 0x77, 0x76, 0x79, 0x79, 0x7c, 0x7b, 0x7e, 0x7d, +0x7f, 0x7e, 0xfe, 0xff, 0xfd, 0xff, 0xfb, 0xfd, 0xfb, 0xfe, 0xfc, 0xfe, +0xfa, 0xfd, 0xfd, 0xfe, 0xf9, 0xfc, 0xf9, 0xfe, 0xfa, 0xff, 0xf9, 0xff, +0xf7, 0xff, 0xf5, 0xfe, 0xf4, 0xfc, 0xf3, 0xfb, 0xf2, 0xf9, 0xf3, 0xf9, +0xf3, 0xf8, 0xf2, 0xf7, 0xf3, 0xf7, 0xf0, 0xf4, 0x7e, 0x78, 0x76, 0x73, +0xe6, 0xe7, 0x7a, 0x76, 0xdf, 0xdf, 0x4e, 0x4c, 0xc6, 0xc2, 0x9f, 0x9f, +0xf9, 0x6d, 0x23, 0x23, 0x32, 0x31, 0x2f, 0x2e, 0x56, 0x59, 0xaf, 0xae, +0xd4, 0xd6, 0x33, 0x32, 0xc9, 0xc5, 0xa5, 0xa4, 0xb7, 0xb7, 0x46, 0x46, +0x58, 0x5e, 0xbd, 0xbb, 0x4c, 0x4b, 0x28, 0x27, 0x32, 0x31, 0xed, 0xed, +0x3a, 0x37, 0x28, 0x26, 0x43, 0x43, 0xac, 0xab, 0xb2, 0xb2, 0x5e, 0x5d, +0xbb, 0xb9, 0xa1, 0x9f, 0xac, 0xac, 0x4e, 0x4d, 0x58, 0x5b, 0xbc, 0xbb, +0x5c, 0x56, 0x27, 0x25, 0x2c, 0x2b, 0xe3, 0xe4, 0x49, 0x45, 0x2d, 0x2c, +0x45, 0x44, 0xe3, 0xee, 0x44, 0x3f, 0x64, 0x65, 0xa5, 0xa3, 0x9b, 0x9a, +0xb7, 0xb8, 0x2f, 0x2e, 0x42, 0x43, 0xc0, 0xbf, 0x3a, 0x38, 0x1c, 0x1b, +0x1f, 0x1e, 0x39, 0x37, 0x34, 0x31, 0x28, 0x26, 0x4f, 0x51, 0xa4, 0xa2, +0xa1, 0x9f, 0xae, 0xac, 0x9e, 0x9c, 0x8f, 0x8e, 0x90, 0x8e, 0x9f, 0x9d, +0xac, 0xa8, 0xb2, 0xaf, 0x2f, 0x2e, 0x12, 0xf, 0xe, 0xc, 0x10, 0xe, +0xd, 0xb, 0xc, 0xa, 0x16, 0x14, 0x59, 0x4e, 0xa8, 0xa7, 0x9c, 0x9a, +0x8d, 0x8b, 0x86, 0x84, 0x89, 0x86, 0x91, 0x8f, 0x99, 0x96, 0xa2, 0x9f, +0x33, 0x31, 0xf, 0xe, 0xb, 0x9, 0xb, 0x9, 0x9, 0x7, 0x8, 0x6, +0x10, 0xe, 0x35, 0x2f, 0xaa, 0xaa, 0x9b, 0x99, 0x8c, 0x8a, 0x84, 0x81, +0x85, 0x83, 0x8c, 0x8a, 0x92, 0x8f, 0x9b, 0x98, 0x44, 0x46, 0x10, 0xf, +0x9, 0x7, 0x8, 0x5, 0x6, 0x3, 0x6, 0x3, 0xd, 0xb, 0x29, 0x25, +0xb4, 0xb6, 0x9d, 0x9c, 0x8c, 0x8a, 0x83, 0x81, 0x83, 0x81, 0x8a, 0x87, +0x8e, 0x8c, 0x96, 0x93, 0xe0, 0xd4, 0x14, 0x12, 0xb, 0xa, 0x9, 0x7, +0x6, 0x3, 0x4, 0x1, 0xa, 0x8, 0x1e, 0x1b, 0x62, 0x4f, 0xa6, 0xa4, +0x8d, 0x8c, 0x84, 0x82, 0x83, 0x81, 0x88, 0x85, 0x8b, 0x88, 0x8f, 0x8d, +0xb0, 0xad, 0x19, 0x17, 0xd, 0xb, 0xa, 0x7, 0x5, 0x2, 0x3, 0x1, +0x9, 0x7, 0x1a, 0x17, 0x3d, 0x36, 0xae, 0xae, 0x90, 0x8e, 0x85, 0x83, +0x84, 0x82, 0x88, 0x85, 0x8a, 0x87, 0x8e, 0x8c, 0xac, 0xa8, 0x1d, 0x1b, +0xe, 0xc, 0xa, 0x8, 0x4, 0x2, 0x2, 0x0, 0x7, 0x4, 0x14, 0xf, +0x2d, 0x28, 0xb9, 0xba, 0x91, 0x8e, 0x85, 0x82, 0x83, 0x81, 0x85, 0x82, +0x88, 0x84, 0x8c, 0x89, 0xa0, 0x9d, 0x23, 0x21, 0xf, 0xd, 0xa, 0x7, +0x4, 0x2, 0x2, 0x0, 0x5, 0x2, 0xf, 0xc, 0x20, 0x1c, 0x6e, 0x54, +0x97, 0x94, 0x86, 0x83, 0x83, 0x80, 0x84, 0x81, 0x85, 0x81, 0x89, 0x85, +0x98, 0x94, 0x30, 0x2f, 0x14, 0x11, 0xb, 0x9, 0x4, 0x2, 0x2, 0x0, +0x3, 0x1, 0xb, 0x8, 0x19, 0x14, 0x32, 0x2c, 0x9c, 0x9a, 0x88, 0x86, +0x83, 0x80, 0x83, 0x81, 0x84, 0x81, 0x86, 0x83, 0x91, 0x8d, 0xf6, 0xd8, +0x1b, 0x19, 0xe, 0xc, 0x5, 0x2, 0x2, 0x0, 0x3, 0x0, 0x9, 0x5, +0x11, 0xd, 0x1f, 0x1c, 0xa9, 0xa8, 0x8c, 0x89, 0x85, 0x82, 0x85, 0x81, +0x84, 0x80, 0x85, 0x81, 0x8e, 0x8b, 0xb2, 0xac, 0x25, 0x24, 0x15, 0x12, +0x8, 0x5, 0x2, 0x0, 0x3, 0x1, 0x8, 0x5, 0xf, 0xc, 0x1a, 0x16, +0xbf, 0xc0, 0x8f, 0x8d, 0x88, 0x85, 0x87, 0x83, 0x85, 0x81, 0x84, 0x81, +0x8c, 0x89, 0xa9, 0xa3, 0x2f, 0x2f, 0x1b, 0x18, 0xc, 0x9, 0x3, 0x0, +0x4, 0x1, 0x9, 0x6, 0xf, 0xb, 0x18, 0x13, 0x68, 0x54, 0x94, 0x90, +0x8a, 0x87, 0x89, 0x86, 0x87, 0x83, 0x86, 0x81, 0x8d, 0x89, 0xa4, 0x9f, +0x3b, 0x3c, 0x1e, 0x1b, 0xe, 0xb, 0x5, 0x1, 0x5, 0x1, 0xb, 0x7, +0x10, 0xd, 0x1a, 0x16, 0xdf, 0xf5, 0x94, 0x91, 0x8b, 0x88, 0x8a, 0x86, +0x88, 0x83, 0x87, 0x82, 0x8e, 0x8a, 0xa7, 0xa1, 0x39, 0x39, 0x1e, 0x1b, +0xe, 0xb, 0x5, 0x2, 0x5, 0x1, 0xb, 0x7, 0x11, 0xd, 0x1b, 0x16, +0xd2, 0xd8, 0x93, 0x8f, 0x8b, 0x88, 0x8a, 0x86, 0x87, 0x82, 0x86, 0x81, +0x8d, 0x89, 0xa7, 0xa1, 0x37, 0x37, 0x1e, 0x1b, 0xe, 0xa, 0x5, 0x1, +0x4, 0x1, 0xa, 0x6, 0xf, 0xb, 0x18, 0x13, 0x54, 0x49, 0x95, 0x92, +0x8b, 0x88, 0x89, 0x85, 0x87, 0x82, 0x85, 0x80, 0x8b, 0x87, 0x9f, 0x9b, +0x4f, 0x59, 0x23, 0x20, 0xf, 0xc, 0x5, 0x2, 0x4, 0x0, 0x9, 0x5, +0xe, 0xa, 0x15, 0xf, 0x37, 0x2f, 0x9a, 0x96, 0x8d, 0x8a, 0x8b, 0x87, +0x88, 0x83, 0x85, 0x81, 0x8b, 0x87, 0x9d, 0x98, 0xe6, 0xcf, 0x28, 0x25, +0x12, 0xe, 0x7, 0x3, 0x5, 0x0, 0xa, 0x5, 0xe, 0xa, 0x15, 0xf, +0x34, 0x2e, 0x9c, 0x99, 0x8e, 0x8b, 0x8b, 0x87, 0x88, 0x83, 0x86, 0x81, +0x8b, 0x87, 0x9c, 0x97, 0xd4, 0xc7, 0x29, 0x27, 0x12, 0xe, 0x8, 0x3, +0x5, 0x1, 0xa, 0x5, 0xe, 0x9, 0x14, 0xe, 0x32, 0x2c, 0x9c, 0x99, +0x8e, 0x8b, 0x8c, 0x88, 0x88, 0x83, 0x85, 0x80, 0x8a, 0x86, 0x9b, 0x96, +0xc4, 0xba, 0x2d, 0x2b, 0x13, 0xf, 0x8, 0x3, 0x5, 0x1, 0x9, 0x5, +0xd, 0x9, 0x12, 0xd, 0x2b, 0x26, 0x9f, 0x9c, 0x8f, 0x8c, 0x8c, 0x88, +0x89, 0x84, 0x85, 0x80, 0x8a, 0x85, 0x9a, 0x94, 0xbd, 0xb5, 0x32, 0x2f, +0x16, 0x10, 0x8, 0x4, 0x5, 0x0, 0x9, 0x4, 0xd, 0x8, 0x11, 0xc, +0x25, 0x1f, 0xa3, 0x9f, 0x8f, 0x8c, 0x8c, 0x88, 0x89, 0x84, 0x85, 0x80, +0x89, 0x84, 0x97, 0x91, 0xb6, 0xae, 0x35, 0x33, 0x17, 0x12, 0x9, 0x4, +0x5, 0x0, 0x8, 0x3, 0xc, 0x7, 0xf, 0xb, 0x22, 0x1c, 0xa7, 0xa3, +0x91, 0x8d, 0x8d, 0x88, 0x89, 0x84, 0x85, 0x80, 0x89, 0x84, 0x95, 0x8f, +0xad, 0xa7, 0x3f, 0x3f, 0x19, 0x13, 0xa, 0x5, 0x5, 0x0, 0x8, 0x2, +0xb, 0x6, 0xe, 0xa, 0x1f, 0x1a, 0xac, 0xa9, 0x94, 0x8f, 0x8e, 0x89, +0x89, 0x84, 0x85, 0x80, 0x88, 0x83, 0x93, 0x8d, 0xa7, 0x9f, 0x5b, 0x6f, +0x1b, 0x16, 0xa, 0x6, 0x6, 0x1, 0x8, 0x2, 0xa, 0x5, 0xd, 0x8, +0x1c, 0x16, 0xb4, 0xaf, 0x96, 0x91, 0x8f, 0x8b, 0x89, 0x84, 0x84, 0x80, +0x87, 0x82, 0x91, 0x8c, 0xa1, 0x9b, 0xc8, 0xbc, 0x1f, 0x1b, 0xb, 0x7, +0x6, 0x1, 0x8, 0x2, 0xa, 0x4, 0xc, 0x7, 0x19, 0x13, 0xbe, 0xbd, +0x99, 0x94, 0x90, 0x8c, 0x8a, 0x85, 0x85, 0x80, 0x87, 0x82, 0x8f, 0x8a, +0x9e, 0x99, 0xbc, 0xb2, 0x23, 0x1e, 0xd, 0x8, 0x7, 0x1, 0x8, 0x2, +0xa, 0x4, 0xc, 0x7, 0x17, 0x11, 0xd5, 0xd9, 0x9b, 0x96, 0x91, 0x8c, +0x8b, 0x85, 0x86, 0x81, 0x87, 0x81, 0x8e, 0x89, 0x9d, 0x97, 0xb6, 0xad, +0x26, 0x21, 0xe, 0xa, 0x8, 0x2, 0x9, 0x2, 0xa, 0x4, 0xc, 0x6, +0x16, 0xf, 0x63, 0x51, 0x9d, 0x9a, 0x93, 0x8e, 0x8b, 0x86, 0x86, 0x80, +0x87, 0x81, 0x8e, 0x89, 0x9b, 0x94, 0xae, 0xa8, 0x2a, 0x25, 0xf, 0xb, +0x9, 0x3, 0x9, 0x3, 0x9, 0x3, 0xb, 0x4, 0x14, 0xe, 0x47, 0x3d, +0xa0, 0x9d, 0x95, 0x8f, 0x8c, 0x87, 0x86, 0x80, 0x87, 0x81, 0x8d, 0x88, +0x99, 0x91, 0xa9, 0xa0, 0x2f, 0x2d, 0x10, 0xc, 0x9, 0x3, 0x9, 0x3, +0x9, 0x3, 0xa, 0x3, 0x12, 0xc, 0x37, 0x2e, 0xa5, 0xa0, 0x98, 0x92, +0x8d, 0x88, 0x86, 0x81, 0x86, 0x81, 0x8d, 0x87, 0x98, 0x90, 0xa5, 0x9d, +0x3b, 0x39, 0x12, 0xd, 0xa, 0x4, 0xa, 0x3, 0xa, 0x3, 0xa, 0x3, +0x10, 0xb, 0x2e, 0x27, 0xa9, 0xa5, 0x9a, 0x94, 0x8e, 0x89, 0x87, 0x81, +0x87, 0x81, 0x8d, 0x87, 0x96, 0x8f, 0xa2, 0x9b, 0x46, 0x45, 0x15, 0xf, +0xb, 0x6, 0xa, 0x4, 0xa, 0x3, 0xa, 0x3, 0xf, 0xa, 0x2b, 0x22, +0xae, 0xac, 0x9c, 0x97, 0x8f, 0x8a, 0x88, 0x82, 0x87, 0x81, 0x8d, 0x87, +0x95, 0x8e, 0x9f, 0x99, 0x56, 0x5d, 0x17, 0x11, 0xc, 0x7, 0xb, 0x5, +0xa, 0x3, 0xa, 0x2, 0xf, 0xa, 0x28, 0x1f, 0xb5, 0xb2, 0x9e, 0x9a, +0x90, 0x8b, 0x89, 0x82, 0x87, 0x81, 0x8c, 0x86, 0x94, 0x8d, 0x9d, 0x96, +0xdb, 0xcc, 0x19, 0x13, 0xd, 0x8, 0xc, 0x6, 0xa, 0x4, 0x9, 0x2, +0xe, 0x9, 0x24, 0x1d, 0xbe, 0xbc, 0xa1, 0x9d, 0x92, 0x8c, 0x89, 0x82, +0x87, 0x80, 0x8c, 0x86, 0x93, 0x8c, 0x9b, 0x93, 0xbf, 0xb6, 0x1c, 0x17, +0xe, 0x9, 0xc, 0x7, 0xb, 0x4, 0x9, 0x2, 0xd, 0x7, 0x20, 0x1a, +0xce, 0xcf, 0xa6, 0x9f, 0x95, 0x8e, 0x8a, 0x84, 0x88, 0x81, 0x8c, 0x85, +0x92, 0x8b, 0x9a, 0x92, 0xb6, 0xad, 0x1f, 0x1a, 0x10, 0xb, 0xd, 0x7, +0xc, 0x5, 0xa, 0x2, 0xd, 0x7, 0x1e, 0x18, 0x64, 0x53, 0xaa, 0xa4, +0x97, 0x8f, 0x8c, 0x85, 0x89, 0x81, 0x8c, 0x85, 0x91, 0x8b, 0x99, 0x90, +0xb0, 0xa9, 0x23, 0x1d, 0x12, 0xc, 0xe, 0x8, 0xc, 0x5, 0xa, 0x2, +0xd, 0x7, 0x1c, 0x15, 0x45, 0x3b, 0xae, 0xaa, 0x99, 0x91, 0x8c, 0x86, +0x89, 0x81, 0x8c, 0x85, 0x90, 0x8a, 0x96, 0x8e, 0xab, 0xa4, 0x28, 0x20, +0x14, 0xd, 0xf, 0x9, 0xc, 0x5, 0x9, 0x2, 0xc, 0x6, 0x1a, 0x12, +0x39, 0x2f, 0xb9, 0xb4, 0x9b, 0x95, 0x8d, 0x86, 0x89, 0x82, 0x8c, 0x85, +0x8f, 0x89, 0x94, 0x8d, 0xa5, 0x9d, 0x2e, 0x28, 0x16, 0xf, 0x10, 0xa, +0xd, 0x6, 0xa, 0x2, 0xc, 0x5, 0x18, 0x10, 0x31, 0x2a, 0xc2, 0xbe, +0x9e, 0x98, 0x8e, 0x88, 0x8a, 0x82, 0x8c, 0x85, 0x8f, 0x89, 0x93, 0x8c, +0xa1, 0x9a, 0x36, 0x2f, 0x19, 0x11, 0x12, 0xb, 0xe, 0x7, 0xa, 0x2, +0xc, 0x4, 0x17, 0xf, 0x2d, 0x26, 0xcf, 0xcd, 0xa0, 0x9a, 0x8f, 0x89, +0x8a, 0x83, 0x8c, 0x84, 0x8f, 0x88, 0x92, 0x8b, 0x9f, 0x98, 0x40, 0x3c, +0x1b, 0x14, 0x13, 0xc, 0xe, 0x7, 0xa, 0x2, 0xc, 0x4, 0x15, 0xd, +0x28, 0x1f, 0x67, 0x58, 0xa4, 0x9c, 0x90, 0x8a, 0x8b, 0x83, 0x8c, 0x84, +0x8e, 0x87, 0x91, 0x8a, 0x9d, 0x96, 0x50, 0x4f, 0x1e, 0x18, 0x15, 0xd, +0xe, 0x8, 0xa, 0x2, 0xb, 0x3, 0x14, 0xc, 0x24, 0x1c, 0x41, 0x39, +0xa9, 0xa1, 0x92, 0x8b, 0x8c, 0x84, 0x8d, 0x85, 0x8e, 0x87, 0x8f, 0x89, +0x9a, 0x92, 0xe4, 0xd3, 0x20, 0x1a, 0x17, 0xf, 0xf, 0x9, 0xb, 0x2, +0xb, 0x3, 0x13, 0xb, 0x21, 0x1a, 0x37, 0x2d, 0xaf, 0xa9, 0x95, 0x8d, +0x8c, 0x85, 0x8d, 0x85, 0x8e, 0x87, 0x8f, 0x88, 0x98, 0x8f, 0xc8, 0xbd, +0x23, 0x1c, 0x19, 0x11, 0x11, 0xa, 0xb, 0x3, 0xb, 0x2, 0x12, 0xa, +0x1f, 0x17, 0x31, 0x29, 0xb8, 0xb1, 0x97, 0x8f, 0x8d, 0x86, 0x8d, 0x86, +0x8e, 0x87, 0x8f, 0x88, 0x97, 0x8e, 0xb9, 0xaf, 0x28, 0x1f, 0x1a, 0x12, +0x12, 0xb, 0xc, 0x4, 0xb, 0x2, 0x11, 0x9, 0x1d, 0x14, 0x2d, 0x24, +0xbe, 0xba, 0x99, 0x91, 0x8e, 0x87, 0x8d, 0x86, 0x8e, 0x87, 0x8f, 0x88, +0x97, 0x8e, 0xb2, 0xaa, 0x2d, 0x27, 0x1c, 0x15, 0x13, 0xb, 0xc, 0x4, +0xb, 0x3, 0x10, 0x9, 0x1b, 0x12, 0x29, 0x1f, 0xc9, 0xc6, 0x9b, 0x93, +0x8f, 0x89, 0x8e, 0x87, 0x8e, 0x87, 0x8e, 0x87, 0x95, 0x8d, 0xae, 0xa5, +0x32, 0x2c, 0x1f, 0x18, 0x15, 0xd, 0xd, 0x4, 0xb, 0x3, 0x10, 0x9, +0x1a, 0x11, 0x25, 0x1c, 0x79, 0x69, 0x9d, 0x95, 0x90, 0x89, 0x8f, 0x87, +0x8f, 0x87, 0x8e, 0x86, 0x93, 0x8b, 0xaa, 0xa0, 0x39, 0x32, 0x23, 0x1b, +0x17, 0xe, 0xd, 0x5, 0xb, 0x2, 0xf, 0x8, 0x1a, 0x10, 0x23, 0x1a, +0x4e, 0x43, 0x9f, 0x98, 0x92, 0x8a, 0x8f, 0x88, 0x8f, 0x87, 0x8e, 0x86, +0x92, 0x8a, 0xa6, 0x9d, 0x3f, 0x3f, 0x26, 0x1e, 0x1a, 0xf, 0xf, 0x6, +0xc, 0x3, 0xf, 0x8, 0x19, 0xf, 0x21, 0x19, 0x41, 0x36, 0xa4, 0x9c, +0x94, 0x8b, 0x90, 0x88, 0x8f, 0x87, 0x8e, 0x86, 0x92, 0x8a, 0xa2, 0x99, +0x66, 0x5b, 0x2a, 0x1f, 0x1b, 0x11, 0xf, 0x7, 0xd, 0x3, 0xf, 0x7, +0x17, 0xe, 0x1e, 0x17, 0x39, 0x2f, 0xa7, 0x9e, 0x96, 0x8d, 0x92, 0x89, +0x8f, 0x87, 0x8e, 0x86, 0x92, 0x89, 0xa0, 0x98, 0xd7, 0xd2, 0x2e, 0x25, +0x1c, 0x13, 0x10, 0x8, 0xd, 0x4, 0xf, 0x7, 0x17, 0xd, 0x1d, 0x13, +0x32, 0x28, 0xab, 0xa0, 0x98, 0x8d, 0x93, 0x8a, 0x90, 0x88, 0x8e, 0x85, +0x91, 0x88, 0x9f, 0x96, 0xc7, 0xc4, 0x34, 0x29, 0x1e, 0x15, 0x11, 0x8, +0xd, 0x3, 0xf, 0x7, 0x16, 0xd, 0x1c, 0x12, 0x2d, 0x25, 0xae, 0xa5, +0x9a, 0x8e, 0x95, 0x8a, 0x91, 0x88, 0x8e, 0x85, 0x90, 0x87, 0x9d, 0x94, +0xbe, 0xbb, 0x3b, 0x2b, 0x22, 0x17, 0x14, 0x9, 0xe, 0x3, 0x10, 0x6, +0x16, 0xc, 0x1b, 0x11, 0x2a, 0x21, 0xb9, 0xaa, 0x9c, 0x8f, 0x96, 0x8a, +0x92, 0x88, 0x8f, 0x85, 0x90, 0x87, 0x9c, 0x91, 0xb6, 0xb0, 0x45, 0x2f, +0x25, 0x18, 0x15, 0xa, 0xf, 0x4, 0x10, 0x6, 0x15, 0xb, 0x1a, 0xf, +0x27, 0x1f, 0xc1, 0xae, 0x9e, 0x90, 0x97, 0x8b, 0x93, 0x88, 0x8f, 0x85, +0x90, 0x86, 0x9b, 0x8f, 0xaf, 0xaa, 0x58, 0x39, 0x28, 0x19, 0x16, 0xa, +0xf, 0x4, 0x10, 0x6, 0x15, 0xa, 0x19, 0xe, 0x25, 0x1c, 0xca, 0xb4, +0xa0, 0x92, 0x99, 0x8b, 0x94, 0x88, 0x8f, 0x84, 0x90, 0x86, 0x9a, 0x8f, +0xad, 0xa6, 0xed, 0x48, 0x2b, 0x1c, 0x18, 0xb, 0x10, 0x4, 0x11, 0x6, +0x15, 0xa, 0x18, 0xd, 0x22, 0x19, 0xde, 0xbf, 0xa3, 0x95, 0x9a, 0x8d, +0x96, 0x89, 0x8f, 0x85, 0x90, 0x85, 0x9a, 0x8e, 0xac, 0xa3, 0xd1, 0x6e, +0x2f, 0x1f, 0x1a, 0xc, 0x10, 0x5, 0x11, 0x6, 0x15, 0xa, 0x18, 0xd, +0x20, 0x17, 0x5b, 0xe6, 0xa6, 0x97, 0x9c, 0x8d, 0x97, 0x8a, 0x91, 0x85, +0x90, 0x85, 0x99, 0x8d, 0xaa, 0x9f, 0xca, 0xd9, 0x33, 0x22, 0x1b, 0xd, +0x12, 0x6, 0x12, 0x6, 0x15, 0x9, 0x18, 0xc, 0x1f, 0x15, 0x49, 0x4c, +0xa9, 0x9a, 0x9d, 0x8e, 0x98, 0x8a, 0x92, 0x86, 0x91, 0x85, 0x99, 0x8d, +0xa7, 0x9d, 0xbf, 0xc3, 0x38, 0x25, 0x1d, 0xe, 0x14, 0x6, 0x13, 0x6, +0x15, 0x9, 0x17, 0xc, 0x1e, 0x14, 0x41, 0x3e, 0xac, 0x9d, 0x9f, 0x90, +0x99, 0x8b, 0x92, 0x86, 0x91, 0x85, 0x99, 0x8c, 0xa6, 0x9b, 0xb9, 0xb6, +0x3e, 0x2b, 0x1e, 0xf, 0x15, 0x7, 0x14, 0x7, 0x16, 0x9, 0x17, 0xb, +0x1d, 0x11, 0x3c, 0x36, 0xaf, 0x9f, 0xa2, 0x93, 0x9b, 0x8c, 0x93, 0x86, +0x91, 0x85, 0x99, 0x8c, 0xa5, 0x99, 0xb5, 0xad, 0x4c, 0x34, 0x20, 0x12, +0x16, 0x8, 0x15, 0x7, 0x17, 0x9, 0x17, 0xb, 0x1c, 0xf, 0x37, 0x2d, +0xb3, 0xa3, 0xa4, 0x94, 0x9c, 0x8d, 0x94, 0x87, 0x91, 0x85, 0x98, 0x8b, +0xa3, 0x97, 0xb2, 0xa9, 0x5c, 0x3f, 0x24, 0x15, 0x17, 0x9, 0x15, 0x7, +0x17, 0x9, 0x17, 0xa, 0x1c, 0xf, 0x32, 0x28, 0xb9, 0xa8, 0xa6, 0x96, +0x9d, 0x8e, 0x95, 0x88, 0x92, 0x85, 0x98, 0x8a, 0xa1, 0x95, 0xaf, 0xa5, +0xf5, 0x51, 0x26, 0x17, 0x19, 0xa, 0x16, 0x8, 0x17, 0x9, 0x17, 0xa, +0x1c, 0xe, 0x2f, 0x24, 0xbf, 0xae, 0xa8, 0x99, 0x9d, 0x8e, 0x96, 0x88, +0x92, 0x85, 0x97, 0x8a, 0x9f, 0x93, 0xac, 0xa0, 0xd5, 0xec, 0x28, 0x19, +0x1a, 0xb, 0x17, 0x9, 0x17, 0x9, 0x16, 0x9, 0x1b, 0xe, 0x2d, 0x20, +0xc7, 0xb5, 0xac, 0x9b, 0x9f, 0x90, 0x96, 0x89, 0x92, 0x85, 0x97, 0x8a, +0x9f, 0x92, 0xa9, 0x9e, 0xc6, 0xc7, 0x2b, 0x1b, 0x1b, 0xc, 0x18, 0x9, +0x18, 0x9, 0x16, 0x9, 0x1a, 0xd, 0x2a, 0x1e, 0xd8, 0xbd, 0xae, 0x9d, +0xa1, 0x91, 0x97, 0x89, 0x93, 0x85, 0x97, 0x89, 0x9e, 0x91, 0xa8, 0x9d, +0xbd, 0xbc, 0x2f, 0x1e, 0x1c, 0xd, 0x19, 0x9, 0x18, 0x9, 0x17, 0x9, +0x1a, 0xc, 0x28, 0x1c, 0x72, 0xce, 0xb3, 0x9f, 0xa4, 0x93, 0x99, 0x8a, +0x94, 0x86, 0x97, 0x88, 0x9e, 0x8f, 0xa7, 0x9b, 0xb9, 0xb3, 0x34, 0x22, +0x1e, 0xe, 0x1a, 0xa, 0x19, 0x9, 0x17, 0x9, 0x19, 0xb, 0x26, 0x18, +0x55, 0x58, 0xb6, 0xa2, 0xa6, 0x95, 0x9a, 0x8b, 0x95, 0x86, 0x97, 0x88, +0x9d, 0x8e, 0xa5, 0x98, 0xb7, 0xad, 0x38, 0x27, 0x1f, 0xf, 0x1b, 0xb, +0x19, 0x9, 0x17, 0x8, 0x19, 0xb, 0x25, 0x17, 0x49, 0x3f, 0xbd, 0xa9, +0xa9, 0x97, 0x9b, 0x8b, 0x95, 0x86, 0x98, 0x88, 0x9d, 0x8e, 0xa3, 0x96, +0xb0, 0xa7, 0x3f, 0x2c, 0x21, 0x11, 0x1c, 0xb, 0x1a, 0xa, 0x18, 0x8, +0x18, 0xa, 0x23, 0x15, 0x3f, 0x39, 0xc8, 0xad, 0xad, 0x9a, 0x9c, 0x8c, +0x96, 0x86, 0x98, 0x88, 0x9d, 0x8e, 0xa1, 0x95, 0xac, 0xa2, 0x4e, 0x34, +0x25, 0x13, 0x1d, 0xc, 0x1c, 0xb, 0x18, 0x9, 0x18, 0x9, 0x20, 0x12, +0x39, 0x2f, 0xdb, 0xb5, 0xb2, 0x9d, 0x9f, 0x8e, 0x97, 0x87, 0x98, 0x88, +0x9c, 0x8d, 0xa0, 0x93, 0xa9, 0x9e, 0x71, 0x42, 0x28, 0x16, 0x1f, 0xd, +0x1c, 0xb, 0x18, 0x9, 0x18, 0x9, 0x1f, 0x10, 0x33, 0x28, 0x69, 0xc1, +0xb6, 0x9f, 0xa0, 0x8f, 0x99, 0x88, 0x99, 0x88, 0x9c, 0x8d, 0x9f, 0x91, +0xa8, 0x9c, 0xdc, 0x5a, 0x2b, 0x19, 0x21, 0xe, 0x1d, 0xc, 0x19, 0x9, +0x18, 0x9, 0x1e, 0xf, 0x2f, 0x24, 0x4d, 0xe3, 0xbc, 0xa3, 0xa2, 0x90, +0x99, 0x89, 0x99, 0x89, 0x9c, 0x8c, 0x9e, 0x91, 0xa6, 0x9b, 0xcd, 0xec, +0x2e, 0x1b, 0x23, 0xf, 0x1e, 0xd, 0x19, 0xa, 0x18, 0x9, 0x1e, 0xf, +0x2e, 0x23, 0x45, 0x5e, 0xc4, 0xa8, 0xa5, 0x92, 0x9a, 0x8a, 0x9a, 0x8a, +0x9d, 0x8d, 0x9e, 0x91, 0xa4, 0x99, 0xc3, 0xcb, 0x31, 0x1c, 0x26, 0x12, +0x20, 0xe, 0x1a, 0xa, 0x18, 0x9, 0x1e, 0xf, 0x2d, 0x22, 0x40, 0x4f, +0xce, 0xac, 0xa8, 0x95, 0x9b, 0x8b, 0x9a, 0x8a, 0x9d, 0x8d, 0x9e, 0x91, +0xa3, 0x99, 0xbc, 0xbe, 0x36, 0x1f, 0x28, 0x13, 0x21, 0xf, 0x1b, 0xb, +0x19, 0xa, 0x1d, 0xf, 0x2b, 0x1f, 0x3d, 0x45, 0xda, 0xaf, 0xaa, 0x97, +0x9d, 0x8c, 0x9b, 0x8a, 0x9d, 0x8d, 0x9e, 0x90, 0xa2, 0x98, 0xb8, 0xb6, +0x3c, 0x23, 0x2a, 0x16, 0x23, 0x10, 0x1c, 0xc, 0x19, 0xa, 0x1d, 0xf, +0x29, 0x1e, 0x38, 0x3d, 0xfe, 0xb3, 0xad, 0x98, 0x9e, 0x8d, 0x9c, 0x8b, +0x9d, 0x8d, 0x9e, 0x90, 0xa1, 0x97, 0xb4, 0xb2, 0x44, 0x26, 0x2d, 0x18, +0x25, 0x12, 0x1d, 0xd, 0x1a, 0xa, 0x1d, 0xf, 0x29, 0x1d, 0x33, 0x35, +0x53, 0xba, 0xaf, 0x99, 0x9f, 0x8d, 0x9d, 0x8c, 0x9e, 0x8d, 0x9d, 0x8f, +0x9f, 0x96, 0xb1, 0xae, 0x4b, 0x2a, 0x31, 0x1a, 0x29, 0x13, 0x1e, 0xd, +0x1a, 0xa, 0x1e, 0xf, 0x29, 0x1d, 0x31, 0x2f, 0x46, 0xc6, 0xb4, 0x9b, +0xa0, 0x8e, 0x9e, 0x8c, 0x9f, 0x8e, 0x9e, 0x8f, 0x9f, 0x95, 0xae, 0xaa, +0x53, 0x2d, 0x34, 0x1b, 0x2b, 0x14, 0x1f, 0xd, 0x1a, 0xb, 0x1d, 0xe, +0x28, 0x1c, 0x2f, 0x2e, 0x42, 0xd1, 0xb8, 0x9e, 0xa3, 0x8f, 0x9f, 0x8c, +0x9f, 0x8d, 0x9e, 0x8f, 0x9f, 0x95, 0xad, 0xa8, 0x66, 0x32, 0x38, 0x1c, +0x2d, 0x15, 0x20, 0xd, 0x1b, 0xb, 0x1d, 0xe, 0x27, 0x19, 0x2e, 0x29, +0x3e, 0xe6, 0xbd, 0x9e, 0xa5, 0x8f, 0x9f, 0x8c, 0x9f, 0x8d, 0x9e, 0x8e, +0x9f, 0x92, 0xac, 0xa3, 0xea, 0x3b, 0x3c, 0x1e, 0x2f, 0x15, 0x21, 0xd, +0x1c, 0xa, 0x1e, 0xd, 0x27, 0x16, 0x2d, 0x22, 0x39, 0x48, 0xc1, 0xa1, +0xa6, 0x8f, 0xa1, 0x8c, 0xa1, 0x8c, 0x9e, 0x8d, 0x9e, 0x8f, 0xab, 0x9e, +0xd9, 0x4b, 0x41, 0x20, 0x33, 0x16, 0x23, 0xd, 0x1c, 0x9, 0x1e, 0xc, +0x27, 0x14, 0x2b, 0x1e, 0x34, 0x37, 0xcc, 0xa5, 0xa8, 0x90, 0xa3, 0x8c, +0xa2, 0x8c, 0x9f, 0x8c, 0x9e, 0x8e, 0xa9, 0x9b, 0xcd, 0xe8, 0x49, 0x25, +0x37, 0x18, 0x25, 0xd, 0x1d, 0x9, 0x1e, 0xb, 0x26, 0x11, 0x2a, 0x1b, +0x31, 0x2e, 0xde, 0xac, 0xab, 0x93, 0xa4, 0x8d, 0xa3, 0x8c, 0x9f, 0x8c, +0x9e, 0x8d, 0xa8, 0x98, 0xc6, 0xc2, 0x4f, 0x29, 0x39, 0x19, 0x27, 0xe, +0x1d, 0x9, 0x1e, 0xa, 0x25, 0xf, 0x2a, 0x19, 0x2f, 0x29, 0x76, 0xb3, +0xad, 0x96, 0xa5, 0x8d, 0xa4, 0x8c, 0x9f, 0x8b, 0x9e, 0x8c, 0xa7, 0x96, +0xbf, 0xb3, 0x5c, 0x2e, 0x3c, 0x1b, 0x28, 0xf, 0x1e, 0x9, 0x1e, 0xa, +0x24, 0xe, 0x28, 0x16, 0x2e, 0x24, 0x5e, 0xbb, 0xaf, 0x98, 0xa6, 0x8e, +0xa4, 0x8c, 0x9f, 0x8b, 0x9e, 0x8c, 0xa6, 0x95, 0xbc, 0xae, 0x74, 0x3a, +0x3f, 0x1e, 0x29, 0xf, 0x1e, 0x9, 0x1e, 0xa, 0x24, 0xe, 0x28, 0x14, +0x2c, 0x1f, 0x51, 0xcc, 0xb1, 0x9a, 0xa8, 0x8f, 0xa6, 0x8d, 0xa0, 0x8b, +0x9e, 0x8b, 0xa5, 0x91, 0xba, 0xa8, 0xe7, 0x4a, 0x46, 0x21, 0x2b, 0x11, +0x1e, 0xa, 0x1f, 0xa, 0x25, 0xd, 0x28, 0x12, 0x2b, 0x1c, 0x4c, 0x6b, +0xb3, 0x9c, 0xa9, 0x90, 0xa7, 0x8d, 0xa1, 0x8a, 0x9e, 0x8a, 0xa5, 0x90, +0xb9, 0xa3, 0xdd, 0xf7, 0x4c, 0x26, 0x2d, 0x13, 0x1f, 0xb, 0x1e, 0xa, +0x24, 0xd, 0x27, 0x11, 0x2b, 0x1a, 0x46, 0x48, 0xb7, 0x9f, 0xaa, 0x92, +0xa7, 0x8d, 0xa0, 0x8a, 0x9e, 0x8a, 0xa3, 0x8f, 0xb3, 0x9e, 0xcd, 0xc8, +0x4f, 0x2a, 0x2e, 0x15, 0x20, 0xb, 0x1f, 0x9, 0x22, 0xc, 0x24, 0xf, +0x29, 0x18, 0x3f, 0x3b, 0xbb, 0xa3, 0xac, 0x94, 0xa7, 0x8d, 0xa0, 0x8a, +0x9d, 0x89, 0xa1, 0x8e, 0xaf, 0x9b, 0xc0, 0xb5, 0x67, 0x30, 0x2f, 0x16, +0x21, 0xc, 0x1f, 0xa, 0x21, 0xb, 0x23, 0xd, 0x26, 0x14, 0x39, 0x2d, +0xc0, 0xa9, 0xae, 0x96, 0xa8, 0x8e, 0x9f, 0x8a, 0x9c, 0x88, 0x9f, 0x8c, +0xac, 0x97, 0xba, 0xaa, 0xe0, 0x41, 0x31, 0x19, 0x21, 0xc, 0x1e, 0xa, +0x1f, 0xb, 0x20, 0xc, 0x23, 0x11, 0x34, 0x25, 0xca, 0xb1, 0xaf, 0x99, +0xa8, 0x8f, 0x9f, 0x8a, 0x9b, 0x88, 0x9e, 0x8b, 0xa9, 0x95, 0xb4, 0xa4, +0xcf, 0x63, 0x34, 0x1c, 0x21, 0xe, 0x1d, 0xa, 0x1e, 0xa, 0x1e, 0xc, +0x20, 0x10, 0x2f, 0x20, 0xd7, 0xbf, 0xb1, 0x9d, 0xa8, 0x91, 0x9e, 0x8b, +0x9a, 0x88, 0x9c, 0x8b, 0xa5, 0x93, 0xae, 0xa0, 0xc7, 0xd0, 0x35, 0x1f, +0x20, 0xf, 0x1c, 0xb, 0x1c, 0xb, 0x1c, 0xb, 0x1e, 0xf, 0x2c, 0x1e, +0xf7, 0xdc, 0xb4, 0xa1, 0xa7, 0x94, 0x9c, 0x8c, 0x98, 0x89, 0x9a, 0x8b, +0xa0, 0x91, 0xaa, 0x9c, 0xbe, 0xbd, 0x35, 0x22, 0x1f, 0x11, 0x1b, 0xc, +0x1b, 0xb, 0x19, 0xb, 0x1b, 0xe, 0x28, 0x1c, 0x59, 0x4d, 0xb7, 0xa7, +0xa7, 0x96, 0x9b, 0x8c, 0x96, 0x89, 0x98, 0x8b, 0x9e, 0x90, 0xa6, 0x99, +0xb7, 0xb1, 0x39, 0x28, 0x1f, 0x14, 0x1b, 0xd, 0x19, 0xb, 0x17, 0xa, +0x19, 0xd, 0x24, 0x19, 0x46, 0x38, 0xbc, 0xae, 0xa7, 0x99, 0x9a, 0x8d, +0x94, 0x8a, 0x96, 0x8b, 0x9c, 0x8f, 0xa1, 0x97, 0xb1, 0xaa, 0x3b, 0x2d, +0x1f, 0x16, 0x1a, 0xe, 0x18, 0xc, 0x15, 0xa, 0x17, 0xd, 0x20, 0x18, +0x3e, 0x2f, 0xbf, 0xb9, 0xa7, 0x9c, 0x99, 0x8e, 0x93, 0x8b, 0x94, 0x8b, +0x9a, 0x8e, 0x9e, 0x95, 0xac, 0xa6, 0x3f, 0x37, 0x1f, 0x19, 0x19, 0x10, +0x16, 0xd, 0x13, 0xb, 0x15, 0xd, 0x1e, 0x16, 0x37, 0x2b, 0xc6, 0xc5, +0xa8, 0x9e, 0x99, 0x8f, 0x92, 0x8b, 0x93, 0x8c, 0x98, 0x8e, 0x9d, 0x94, +0xaa, 0xa3, 0x47, 0x3f, 0x21, 0x1c, 0x1a, 0x12, 0x16, 0xd, 0x13, 0xb, +0x14, 0xd, 0x1d, 0x15, 0x33, 0x27, 0xcf, 0xd8, 0xaa, 0xa0, 0x9a, 0x91, +0x92, 0x8c, 0x93, 0x8c, 0x98, 0x8e, 0x9c, 0x93, 0xa8, 0xa0, 0x55, 0x53, +0x22, 0x1e, 0x1a, 0x13, 0x17, 0xe, 0x13, 0xb, 0x13, 0xd, 0x1c, 0x14, +0x2f, 0x24, 0xdb, 0x5c, 0xab, 0xa5, 0x9a, 0x93, 0x93, 0x8d, 0x93, 0x8c, +0x97, 0x8e, 0x9b, 0x92, 0xa6, 0x9e, 0x6b, 0xeb, 0x24, 0x20, 0x1b, 0x16, +0x17, 0xf, 0x13, 0xc, 0x13, 0xd, 0x1b, 0x14, 0x2c, 0x21, 0x6c, 0x46, +0xae, 0xa9, 0x9b, 0x95, 0x93, 0x8e, 0x92, 0x8d, 0x96, 0x8e, 0x9a, 0x92, +0xa2, 0x9c, 0xd5, 0xcb, 0x27, 0x25, 0x1c, 0x17, 0x17, 0xf, 0x12, 0xd, +0x12, 0xd, 0x19, 0x13, 0x29, 0x1f, 0x4f, 0x3e, 0xb2, 0xac, 0x9d, 0x97, +0x93, 0x8e, 0x92, 0x8d, 0x95, 0x8e, 0x99, 0x92, 0xa0, 0x9c, 0xc6, 0xc1, +0x2a, 0x28, 0x1d, 0x19, 0x18, 0x10, 0x12, 0xd, 0x11, 0xd, 0x18, 0x13, +0x26, 0x1e, 0x43, 0x3a, 0xb8, 0xae, 0x9e, 0x99, 0x94, 0x8f, 0x92, 0x8d, +0x95, 0x8e, 0x98, 0x91, 0x9e, 0x9b, 0xbb, 0xba, 0x2e, 0x2c, 0x1e, 0x1a, +0x18, 0x12, 0x12, 0xd, 0x11, 0xd, 0x17, 0x12, 0x23, 0x1d, 0x3a, 0x32, +0xbe, 0xb6, 0x9f, 0x9b, 0x94, 0x90, 0x92, 0x8e, 0x94, 0x8e, 0x97, 0x90, +0x9c, 0x99, 0xb3, 0xb2, 0x32, 0x31, 0x1f, 0x1d, 0x19, 0x13, 0x12, 0xe, +0x10, 0xd, 0x15, 0x11, 0x1f, 0x1b, 0x33, 0x2d, 0xcc, 0xbf, 0xa1, 0x9c, +0x95, 0x91, 0x91, 0x8e, 0x93, 0x8e, 0x95, 0x90, 0x9a, 0x98, 0xad, 0xad, +0x38, 0x37, 0x20, 0x1e, 0x19, 0x15, 0x12, 0xe, 0xf, 0xd, 0x13, 0x11, +0x1d, 0x1a, 0x2e, 0x2a, 0xd7, 0xc7, 0xa2, 0x9e, 0x95, 0x92, 0x91, 0x8f, +0x92, 0x8f, 0x94, 0x90, 0x99, 0x98, 0xaa, 0xac, 0x3e, 0x3b, 0x21, 0x1f, +0x19, 0x16, 0x12, 0xf, 0xf, 0xd, 0x12, 0x11, 0x1c, 0x1a, 0x2b, 0x29, +0x6b, 0xd2, 0xa5, 0x9f, 0x96, 0x94, 0x90, 0x8f, 0x91, 0x8f, 0x93, 0x90, +0x97, 0x97, 0xa6, 0xaa, 0x4b, 0x42, 0x24, 0x22, 0x1a, 0x17, 0x12, 0xf, +0xe, 0xd, 0x11, 0x11, 0x1a, 0x19, 0x28, 0x27, 0x4f, 0xe7, 0xa8, 0xa1, +0x97, 0x95, 0x91, 0x8f, 0x90, 0x8f, 0x92, 0x8f, 0x96, 0x97, 0xa3, 0xa8, +0x66, 0x4b, 0x27, 0x23, 0x1b, 0x17, 0x13, 0xf, 0xe, 0xe, 0x10, 0x10, +0x18, 0x18, 0x24, 0x26, 0x41, 0x72, 0xab, 0xa2, 0x98, 0x95, 0x91, 0x90, +0x90, 0x8f, 0x91, 0x8f, 0x95, 0x96, 0xa0, 0xa5, 0xdd, 0x55, 0x29, 0x24, +0x1c, 0x17, 0x13, 0xf, 0xe, 0xe, 0xf, 0x10, 0x17, 0x18, 0x22, 0x24, +0x3b, 0x57, 0xae, 0xa4, 0x99, 0x96, 0x92, 0x8f, 0x90, 0x8e, 0x90, 0x8f, +0x94, 0x95, 0x9e, 0xa4, 0xc9, 0x62, 0x2c, 0x26, 0x1c, 0x18, 0x13, 0xf, +0xe, 0xd, 0xf, 0xf, 0x16, 0x17, 0x1f, 0x22, 0x36, 0x4e, 0xb2, 0xa6, +0x9a, 0x96, 0x92, 0x8f, 0x90, 0x8e, 0x8f, 0x8f, 0x92, 0x94, 0x9d, 0xa2, +0xbe, 0xe4, 0x2e, 0x28, 0x1d, 0x19, 0x14, 0xf, 0xe, 0xd, 0xe, 0xf, +0x15, 0x16, 0x1e, 0x20, 0x2f, 0x42, 0xb9, 0xa8, 0x9b, 0x97, 0x93, 0x90, +0x90, 0x8e, 0x8f, 0x8e, 0x91, 0x93, 0x9b, 0x9f, 0xb6, 0xcf, 0x34, 0x2a, +0x1f, 0x1a, 0x15, 0x10, 0xe, 0xd, 0xe, 0xf, 0x13, 0x15, 0x1c, 0x1e, +0x2b, 0x3b, 0xc0, 0xab, 0x9d, 0x98, 0x93, 0x91, 0x90, 0x8f, 0x8f, 0x8f, +0x90, 0x92, 0x99, 0x9e, 0xaf, 0xc4, 0x3c, 0x2d, 0x21, 0x1b, 0x16, 0x11, +0xe, 0xe, 0xe, 0xf, 0x12, 0x15, 0x1a, 0x1d, 0x28, 0x36, 0xd1, 0xae, +0x9f, 0x99, 0x94, 0x91, 0x90, 0x8f, 0x8f, 0x8e, 0x8f, 0x92, 0x97, 0x9d, +0xab, 0xbc, 0x46, 0x2f, 0x23, 0x1c, 0x17, 0x12, 0xf, 0xe, 0xe, 0xe, +0x11, 0x14, 0x19, 0x1d, 0x25, 0x33, 0xfc, 0xb1, 0xa1, 0x9a, 0x95, 0x92, +0x90, 0x8e, 0x8f, 0x8e, 0x8f, 0x92, 0x96, 0x9c, 0xa7, 0xb7, 0x56, 0x32, +0x26, 0x1c, 0x18, 0x12, 0xf, 0xe, 0xe, 0xe, 0x10, 0x13, 0x18, 0x1c, +0x22, 0x2f, 0x53, 0xb5, 0xa4, 0x9b, 0x96, 0x92, 0x91, 0x8f, 0x8f, 0x8e, +0x8f, 0x91, 0x95, 0x9b, 0xa5, 0xb3, 0xfa, 0x36, 0x29, 0x1e, 0x19, 0x13, +0xf, 0xe, 0xe, 0xe, 0x10, 0x12, 0x17, 0x1a, 0x1f, 0x2c, 0x47, 0xb9, +0xa6, 0x9c, 0x97, 0x93, 0x91, 0x8f, 0x8f, 0x8e, 0x8e, 0x90, 0x94, 0x9a, +0xa2, 0xaf, 0xd4, 0x3b, 0x2b, 0x1e, 0x19, 0x13, 0xf, 0xe, 0xe, 0xe, +0xf, 0x11, 0x15, 0x19, 0x1e, 0x29, 0x3e, 0xbf, 0xa9, 0x9d, 0x98, 0x94, +0x91, 0x8f, 0x8e, 0x8e, 0x8e, 0x8f, 0x93, 0x98, 0xa0, 0xac, 0xc6, 0x44, +0x2d, 0x20, 0x1a, 0x14, 0x10, 0xe, 0xe, 0xd, 0xf, 0x10, 0x14, 0x18, +0x1d, 0x26, 0x38, 0xcf, 0xac, 0x9f, 0x99, 0x94, 0x92, 0x8f, 0x8f, 0x8e, +0x8e, 0x8f, 0x92, 0x97, 0x9e, 0xa8, 0xbc, 0x50, 0x31, 0x23, 0x1c, 0x15, +0x11, 0xe, 0xe, 0xd, 0xf, 0xf, 0x13, 0x17, 0x1c, 0x24, 0x31, 0xe7, +0xaf, 0xa1, 0x9b, 0x95, 0x93, 0x8f, 0x8e, 0x8d, 0x8e, 0x8f, 0x91, 0x96, +0x9c, 0xa6, 0xb6, 0x79, 0x37, 0x26, 0x1d, 0x16, 0x12, 0xf, 0xe, 0xe, +0xe, 0xf, 0x12, 0x16, 0x1a, 0x20, 0x2d, 0x57, 0xb5, 0xa4, 0x9c, 0x97, +0x93, 0x90, 0x8f, 0x8e, 0x8e, 0x8e, 0x90, 0x95, 0x9b, 0xa3, 0xb0, 0xd2, +0x3c, 0x29, 0x1e, 0x18, 0x13, 0xf, 0xe, 0xe, 0xe, 0xf, 0x12, 0x15, +0x19, 0x1f, 0x2b, 0x4a, 0xba, 0xa7, 0x9d, 0x98, 0x95, 0x91, 0x8f, 0x8e, +0x8e, 0x8e, 0x90, 0x95, 0x9a, 0xa2, 0xad, 0xcb, 0x44, 0x2b, 0x1f, 0x19, +0x14, 0x10, 0xe, 0xe, 0xe, 0xf, 0x11, 0x15, 0x18, 0x1e, 0x29, 0x3f, +0xc0, 0xaa, 0x9e, 0x99, 0x95, 0x91, 0x8f, 0x8e, 0x8e, 0x8e, 0x8f, 0x94, +0x99, 0x9f, 0xab, 0xc1, 0x4c, 0x2d, 0x21, 0x1a, 0x14, 0x10, 0xe, 0xe, +0xe, 0xf, 0x10, 0x14, 0x18, 0x1d, 0x27, 0x3a, 0xc9, 0xac, 0x9f, 0x9a, +0x95, 0x92, 0x8f, 0x8e, 0x8d, 0x8e, 0x8f, 0x93, 0x98, 0x9e, 0xa9, 0xba, +0x58, 0x30, 0x23, 0x1b, 0x15, 0x11, 0xe, 0xe, 0xe, 0xf, 0xf, 0x13, +0x16, 0x1c, 0x24, 0x34, 0xd6, 0xb0, 0xa1, 0x9b, 0x96, 0x93, 0x8f, 0x8f, +0x8d, 0x8e, 0x8e, 0x92, 0x96, 0x9c, 0xa5, 0xb5, 0x7e, 0x36, 0x24, 0x1d, +0x15, 0x12, 0xe, 0xe, 0xd, 0xf, 0xf, 0x13, 0x15, 0x1b, 0x21, 0x2f, +0x6e, 0xb4, 0xa3, 0x9c, 0x96, 0x94, 0x8f, 0x8f, 0x8d, 0x8e, 0x8e, 0x92, +0x95, 0x9c, 0xa2, 0xb1, 0xd2, 0x3b, 0x26, 0x1e, 0x16, 0x13, 0xe, 0xf, +0xd, 0xf, 0xe, 0x12, 0x14, 0x1a, 0x1f, 0x2d, 0x55, 0xba, 0xa5, 0x9e, +0x97, 0x95, 0x8f, 0x8f, 0x8d, 0x8e, 0x8e, 0x91, 0x94, 0x9b, 0xa0, 0xae, +0xca, 0x41, 0x28, 0x1f, 0x17, 0x14, 0xf, 0xf, 0xd, 0xf, 0xe, 0x12, +0x13, 0x19, 0x1e, 0x2b, 0x4a, 0xbe, 0xa7, 0x9f, 0x98, 0x96, 0x8f, 0x8f, +0x8d, 0x8e, 0x8e, 0x91, 0x93, 0x9a, 0x9e, 0xac, 0xbf, 0x4b, 0x2a, 0x21, +0x17, 0x15, 0xf, 0xf, 0xd, 0xf, 0xe, 0x11, 0x12, 0x19, 0x1d, 0x28, +0x40, 0xc9, 0xa9, 0xa0, 0x98, 0x96, 0x8f, 0x90, 0x8d, 0x8e, 0x8d, 0x90, +0x92, 0x99, 0x9d, 0xa9, 0xbc, 0x57, 0x2c, 0x23, 0x18, 0x16, 0xf, 0xf, +0xd, 0xf, 0xd, 0x11, 0x11, 0x18, 0x1c, 0x26, 0x3b, 0xcf, 0xab, 0xa2, +0x98, 0x97, 0x8f, 0x90, 0x8c, 0x8e, 0x8d, 0x90, 0x91, 0x98, 0x9c, 0xa8, +0xb8, 0x73, 0x2d, 0x26, 0x18, 0x17, 0xf, 0xf, 0xd, 0xf, 0xd, 0x11, +0x10, 0x17, 0x1b, 0x24, 0x36, 0xea, 0xac, 0xa3, 0x99, 0x98, 0x8f, 0x91, +0x8c, 0x8e, 0x8c, 0x8f, 0x90, 0x98, 0x9b, 0xa7, 0xb5, 0xee, 0x30, 0x27, +0x19, 0x17, 0xf, 0xf, 0xc, 0xf, 0xd, 0x11, 0xf, 0x17, 0x19, 0x22, +0x30, 0x6b, 0xae, 0xa4, 0x99, 0x98, 0x90, 0x92, 0x8c, 0x8f, 0x8c, 0x8f, +0x8f, 0x97, 0x9a, 0xa6, 0xb0, 0xe1, 0x36, 0x2a, 0x1a, 0x19, 0xf, 0x10, +0xc, 0xf, 0xc, 0x11, 0xf, 0x17, 0x18, 0x20, 0x2c, 0x4f, 0xb2, 0xa6, +0x9a, 0x99, 0x90, 0x92, 0x8c, 0x8f, 0x8b, 0x8f, 0x8e, 0x96, 0x99, 0xa5, +0xac, 0xce, 0x3c, 0x2c, 0x1c, 0x1a, 0xf, 0x11, 0xc, 0xf, 0xc, 0x11, +0xe, 0x16, 0x16, 0x1f, 0x29, 0x47, 0xb8, 0xa9, 0x9c, 0x9a, 0x91, 0x94, +0x8d, 0x8f, 0x8b, 0x8f, 0x8e, 0x96, 0x97, 0xa3, 0xa9, 0xc4, 0x43, 0x2f, +0x1d, 0x1b, 0x10, 0x12, 0xc, 0xf, 0xc, 0x11, 0xe, 0x16, 0x15, 0x1f, +0x26, 0x41, 0xbe, 0xab, 0x9d, 0x9b, 0x92, 0x94, 0x8d, 0x8f, 0x8b, 0x8f, +0x8e, 0x96, 0x96, 0xa2, 0xa6, 0xc0, 0x4e, 0x30, 0x1e, 0x1c, 0x11, 0x12, +0xc, 0x10, 0xc, 0x12, 0xd, 0x16, 0x14, 0x1e, 0x24, 0x3d, 0xca, 0xad, +0x9e, 0x9c, 0x93, 0x95, 0x8d, 0x90, 0x8b, 0x8f, 0x8d, 0x96, 0x94, 0xa0, +0xa3, 0xbb, 0x6e, 0x36, 0x1f, 0x1d, 0x12, 0x13, 0xd, 0x10, 0xb, 0x11, +0xd, 0x15, 0x12, 0x1d, 0x20, 0x37, 0xde, 0xb0, 0xa0, 0x9e, 0x93, 0x96, +0x8d, 0x90, 0x8b, 0x8f, 0x8c, 0x95, 0x93, 0x9f, 0x9f, 0xb5, 0xd7, 0x3b, +0x21, 0x1e, 0x12, 0x14, 0xc, 0x10, 0xb, 0x11, 0xc, 0x14, 0x10, 0x1c, +0x1e, 0x33, 0x60, 0xb5, 0xa2, 0x9e, 0x94, 0x97, 0x8d, 0x90, 0x8a, 0x8f, +0x8c, 0x94, 0x91, 0x9e, 0x9e, 0xb1, 0xc7, 0x3f, 0x24, 0x1f, 0x13, 0x15, +0xd, 0x10, 0xb, 0x11, 0xc, 0x14, 0xf, 0x1b, 0x1d, 0x30, 0x48, 0xb8, +0xa5, 0x9f, 0x95, 0x97, 0x8d, 0x91, 0x8a, 0x8f, 0x8b, 0x94, 0x8f, 0x9d, +0x9c, 0xae, 0xbd, 0x45, 0x27, 0x1f, 0x14, 0x15, 0xd, 0x11, 0xb, 0x11, +0xb, 0x13, 0xf, 0x1a, 0x1b, 0x2d, 0x3d, 0xbd, 0xa9, 0xa1, 0x96, 0x98, +0x8d, 0x91, 0x8a, 0x8f, 0x8b, 0x93, 0x8f, 0x9c, 0x9a, 0xac, 0xb5, 0x4f, +0x2a, 0x22, 0x15, 0x16, 0xd, 0x11, 0xb, 0x11, 0xb, 0x13, 0xe, 0x1a, +0x19, 0x2b, 0x35, 0xc3, 0xac, 0xa3, 0x97, 0x98, 0x8d, 0x91, 0x8a, 0x8f, +0x8b, 0x93, 0x8e, 0x9c, 0x98, 0xab, 0xaf, 0x5b, 0x2d, 0x24, 0x17, 0x17, +0xe, 0x12, 0xb, 0x11, 0xa, 0x13, 0xd, 0x19, 0x18, 0x2a, 0x2f, 0xc9, +0xb0, 0xa4, 0x99, 0x99, 0x8e, 0x92, 0x8a, 0x8f, 0x8b, 0x93, 0x8e, 0x9b, +0x97, 0xa9, 0xab, 0x72, 0x32, 0x25, 0x18, 0x18, 0xe, 0x12, 0xb, 0x11, +0xa, 0x12, 0xd, 0x19, 0x16, 0x28, 0x2b, 0xd3, 0xb6, 0xa6, 0x9a, 0x9a, +0x8e, 0x92, 0x8a, 0x8f, 0x8a, 0x92, 0x8d, 0x9a, 0x95, 0xa7, 0xa8, 0xdc, +0x36, 0x27, 0x19, 0x18, 0xf, 0x13, 0xb, 0x11, 0xa, 0x12, 0xc, 0x18, +0x15, 0x26, 0x28, 0xf3, 0xbd, 0xa9, 0x9b, 0x9b, 0x8e, 0x92, 0x8a, 0x8f, +0x8a, 0x92, 0x8d, 0x99, 0x93, 0xa4, 0xa4, 0xcb, 0x3d, 0x2a, 0x1b, 0x19, +0xf, 0x13, 0xb, 0x11, 0xa, 0x12, 0xc, 0x17, 0x13, 0x24, 0x25, 0x5b, +0xc9, 0xab, 0x9d, 0x9c, 0x8f, 0x93, 0x8b, 0x8f, 0x8a, 0x92, 0x8c, 0x98, +0x92, 0xa2, 0xa1, 0xbf, 0x4c, 0x2d, 0x1d, 0x1b, 0x10, 0x14, 0xb, 0x11, +0xa, 0x11, 0xb, 0x16, 0x12, 0x21, 0x21, 0x4a, 0xdd, 0xae, 0x9e, 0x9d, +0x90, 0x94, 0x8b, 0x8f, 0x8a, 0x91, 0x8c, 0x98, 0x91, 0xa0, 0x9f, 0xba, +0x6c, 0x2f, 0x1e, 0x1c, 0x10, 0x15, 0xb, 0x12, 0xa, 0x11, 0xb, 0x16, +0x10, 0x1f, 0x1f, 0x3f, 0x6f, 0xb2, 0x9f, 0x9e, 0x91, 0x95, 0x8b, 0x90, +0x89, 0x91, 0x8b, 0x97, 0x90, 0x9f, 0x9d, 0xb6, 0xd5, 0x35, 0x1f, 0x1d, +0x11, 0x15, 0xb, 0x12, 0x9, 0x11, 0xb, 0x15, 0xf, 0x1e, 0x1d, 0x3b, +0x52, 0xb4, 0xa1, 0x9f, 0x92, 0x96, 0x8b, 0x90, 0x89, 0x91, 0x8b, 0x96, +0x8f, 0x9e, 0x9c, 0xb2, 0xc6, 0x3a, 0x22, 0x1e, 0x12, 0x16, 0xc, 0x12, +0xa, 0x12, 0xa, 0x15, 0xe, 0x1d, 0x1c, 0x35, 0x45, 0xba, 0xa4, 0xa1, +0x93, 0x97, 0x8c, 0x91, 0x89, 0x91, 0x8a, 0x96, 0x8f, 0x9d, 0x9a, 0xae, +0xbb, 0x41, 0x25, 0x1f, 0x13, 0x17, 0xc, 0x12, 0x9, 0x11, 0xa, 0x14, +0xe, 0x1c, 0x1a, 0x30, 0x3a, 0xc0, 0xa8, 0xa3, 0x94, 0x98, 0x8c, 0x92, +0x89, 0x91, 0x8a, 0x95, 0x8e, 0x9c, 0x98, 0xac, 0xb3, 0x4b, 0x2a, 0x23, +0x15, 0x18, 0xd, 0x13, 0xa, 0x12, 0x9, 0x14, 0xd, 0x1b, 0x18, 0x2d, +0x31, 0xca, 0xac, 0xa6, 0x96, 0x99, 0x8c, 0x93, 0x89, 0x91, 0x8a, 0x95, +0x8d, 0x9c, 0x96, 0xaa, 0xae, 0x59, 0x2c, 0x25, 0x16, 0x19, 0xd, 0x14, +0xa, 0x12, 0x9, 0x14, 0xc, 0x1b, 0x16, 0x2b, 0x2d, 0xda, 0xaf, 0xa8, +0x97, 0x9a, 0x8d, 0x93, 0x89, 0x91, 0x89, 0x95, 0x8c, 0x9b, 0x95, 0xa8, +0xaa, 0xef, 0x2f, 0x27, 0x17, 0x1a, 0xd, 0x15, 0x9, 0x12, 0x9, 0x13, +0xc, 0x1a, 0x15, 0x29, 0x2a, 0x6e, 0xb4, 0xab, 0x98, 0x9b, 0x8d, 0x94, +0x89, 0x92, 0x89, 0x94, 0x8c, 0x9a, 0x93, 0xa5, 0xa8, 0xd4, 0x33, 0x2a, +0x18, 0x1c, 0xd, 0x15, 0x9, 0x12, 0x8, 0x13, 0xb, 0x19, 0x13, 0x26, +0x27, 0x4f, 0xb9, 0xae, 0x99, 0x9d, 0x8d, 0x95, 0x89, 0x92, 0x89, 0x94, +0x8b, 0x99, 0x92, 0xa3, 0xa5, 0xc7, 0x3a, 0x2d, 0x19, 0x1d, 0xe, 0x17, +0x9, 0x13, 0x8, 0x13, 0xb, 0x19, 0x12, 0x25, 0x24, 0x46, 0xc0, 0xb2, +0x9a, 0x9e, 0x8d, 0x96, 0x89, 0x93, 0x88, 0x94, 0x8a, 0x99, 0x90, 0xa1, +0xa0, 0xbe, 0x40, 0x30, 0x1a, 0x1e, 0xe, 0x17, 0x9, 0x13, 0x7, 0x13, +0xa, 0x18, 0x10, 0x23, 0x1f, 0x3e, 0xd3, 0xb7, 0x9b, 0x9f, 0x8d, 0x96, +0x89, 0x93, 0x88, 0x94, 0x8a, 0x98, 0x8f, 0x9f, 0x9e, 0xb9, 0x50, 0x35, +0x1c, 0x1f, 0xe, 0x18, 0x9, 0x14, 0x7, 0x13, 0x9, 0x18, 0xf, 0x21, +0x1d, 0x39, 0x5e, 0xbd, 0x9d, 0xa1, 0x8e, 0x98, 0x89, 0x94, 0x88, 0x94, +0x89, 0x98, 0x8e, 0x9e, 0x9b, 0xb4, 0xe5, 0x3b, 0x1e, 0x22, 0xf, 0x19, +0x9, 0x14, 0x7, 0x13, 0x8, 0x17, 0xe, 0x1f, 0x1b, 0x34, 0x45, 0xc4, +0x9f, 0xa4, 0x8f, 0x99, 0x89, 0x95, 0x87, 0x95, 0x89, 0x98, 0x8d, 0x9e, +0x99, 0xb0, 0xc9, 0x40, 0x20, 0x25, 0x10, 0x1b, 0xa, 0x15, 0x7, 0x14, +0x8, 0x17, 0xd, 0x1f, 0x19, 0x2f, 0x3a, 0xcf, 0xa3, 0xa7, 0x8f, 0x9a, +0x89, 0x95, 0x87, 0x95, 0x88, 0x97, 0x8c, 0x9d, 0x97, 0xad, 0xbc, 0x4c, +0x23, 0x27, 0x12, 0x1c, 0xa, 0x16, 0x6, 0x14, 0x7, 0x17, 0xc, 0x1e, +0x17, 0x2d, 0x31, 0xe6, 0xa7, 0xaa, 0x91, 0x9b, 0x8a, 0x96, 0x87, 0x95, +0x88, 0x97, 0x8b, 0x9c, 0x95, 0xab, 0xb2, 0x60, 0x28, 0x2a, 0x13, 0x1d, +0xa, 0x17, 0x6, 0x14, 0x7, 0x17, 0xb, 0x1d, 0x14, 0x2b, 0x2b, 0x5e, +0xab, 0xac, 0x92, 0x9d, 0x8a, 0x97, 0x87, 0x95, 0x87, 0x97, 0x8a, 0x9c, +0x92, 0xa9, 0xab, 0xdf, 0x2c, 0x2d, 0x15, 0x1e, 0xb, 0x18, 0x6, 0x15, +0x6, 0x17, 0xa, 0x1c, 0x12, 0x29, 0x26, 0x50, 0xb1, 0xae, 0x94, 0x9e, +0x8a, 0x98, 0x87, 0x96, 0x86, 0x97, 0x89, 0x9c, 0x90, 0xa8, 0xa5, 0xcf, +0x33, 0x2f, 0x16, 0x1f, 0xb, 0x19, 0x6, 0x16, 0x5, 0x17, 0x9, 0x1c, +0xf, 0x27, 0x22, 0x49, 0xba, 0xb1, 0x97, 0x9f, 0x8b, 0x99, 0x87, 0x96, +0x86, 0x97, 0x88, 0x9c, 0x8f, 0xa7, 0xa0, 0xc7, 0x3d, 0x34, 0x18, 0x20, +0xc, 0x1a, 0x7, 0x17, 0x5, 0x17, 0x8, 0x1b, 0xe, 0x26, 0x1e, 0x43, +0xcb, 0xb6, 0x99, 0xa2, 0x8c, 0x9a, 0x87, 0x97, 0x86, 0x97, 0x88, 0x9b, +0x8d, 0xa5, 0x9d, 0xbe, 0x4e, 0x39, 0x1a, 0x23, 0xd, 0x1b, 0x7, 0x17, +0x5, 0x17, 0x7, 0x1b, 0xd, 0x24, 0x1c, 0x3c, 0xf9, 0xbc, 0x9b, 0xa4, +0x8d, 0x9b, 0x87, 0x97, 0x85, 0x98, 0x87, 0x9b, 0x8d, 0xa3, 0x9b, 0xb9, +0xe7, 0x3e, 0x1c, 0x25, 0xd, 0x1c, 0x7, 0x18, 0x5, 0x18, 0x7, 0x1b, +0xc, 0x23, 0x19, 0x38, 0x4b, 0xc2, 0x9d, 0xa7, 0x8d, 0x9c, 0x87, 0x98, +0x85, 0x98, 0x86, 0x9b, 0x8b, 0xa2, 0x98, 0xb5, 0xc6, 0x47, 0x1e, 0x28, +0xe, 0x1d, 0x8, 0x19, 0x4, 0x18, 0x6, 0x1b, 0xb, 0x21, 0x17, 0x34, +0x3a, 0xcb, 0x9f, 0xa9, 0x8e, 0x9d, 0x88, 0x99, 0x85, 0x98, 0x86, 0x9b, +0x8a, 0xa1, 0x96, 0xb2, 0xb8, 0x4f, 0x22, 0x2a, 0xf, 0x1e, 0x8, 0x1a, +0x4, 0x18, 0x5, 0x1b, 0xa, 0x21, 0x14, 0x31, 0x30, 0xd7, 0xa4, 0xac, +0x8f, 0x9e, 0x88, 0x9a, 0x85, 0x99, 0x85, 0x9b, 0x89, 0xa0, 0x93, 0xaf, +0xaf, 0x5f, 0x26, 0x2c, 0x10, 0x1f, 0x8, 0x1a, 0x4, 0x19, 0x5, 0x1a, +0x9, 0x20, 0x12, 0x2f, 0x2a, 0xf0, 0xa9, 0xae, 0x90, 0x9f, 0x89, 0x9a, +0x85, 0x99, 0x85, 0x9b, 0x89, 0x9f, 0x91, 0xad, 0xa9, 0xf2, 0x2c, 0x2e, +0x12, 0x20, 0x9, 0x1b, 0x5, 0x19, 0x5, 0x1a, 0x9, 0x1f, 0x10, 0x2d, +0x25, 0x60, 0xae, 0xb1, 0x93, 0xa1, 0x8a, 0x9b, 0x85, 0x99, 0x85, 0x9b, +0x88, 0x9f, 0x8f, 0xab, 0xa4, 0xd6, 0x34, 0x31, 0x15, 0x22, 0xa, 0x1c, +0x5, 0x19, 0x4, 0x1a, 0x8, 0x1f, 0xe, 0x2c, 0x1f, 0x52, 0xb8, 0xb4, +0x95, 0xa3, 0x8a, 0x9c, 0x86, 0x99, 0x84, 0x9b, 0x87, 0x9f, 0x8e, 0xab, +0xa0, 0xce, 0x3d, 0x34, 0x18, 0x23, 0xb, 0x1c, 0x5, 0x1a, 0x4, 0x1a, +0x7, 0x1f, 0xd, 0x2b, 0x1d, 0x4b, 0xc6, 0xb7, 0x97, 0xa4, 0x8b, 0x9c, +0x86, 0x9a, 0x84, 0x9b, 0x86, 0x9e, 0x8d, 0xa9, 0x9d, 0xc8, 0x4e, 0x38, +0x1a, 0x25, 0xc, 0x1d, 0x6, 0x1a, 0x4, 0x1a, 0x7, 0x1e, 0xd, 0x2a, +0x1a, 0x44, 0xe2, 0xbb, 0x99, 0xa6, 0x8c, 0x9d, 0x87, 0x9a, 0x85, 0x9b, +0x86, 0x9e, 0x8c, 0xa8, 0x9b, 0xc2, 0xe2, 0x3c, 0x1c, 0x27, 0xd, 0x1e, +0x7, 0x1b, 0x5, 0x1b, 0x7, 0x1e, 0xc, 0x29, 0x19, 0x3f, 0x51, 0xbf, +0x9c, 0xa8, 0x8d, 0x9e, 0x88, 0x9b, 0x85, 0x9b, 0x86, 0x9e, 0x8c, 0xa8, +0x99, 0xbe, 0xc7, 0x3f, 0x1f, 0x29, 0xe, 0x1f, 0x7, 0x1b, 0x5, 0x1b, +0x7, 0x1e, 0xc, 0x28, 0x17, 0x3c, 0x3f, 0xc5, 0x9e, 0xaa, 0x8e, 0x9f, +0x88, 0x9c, 0x85, 0x9c, 0x86, 0x9e, 0x8b, 0xa7, 0x98, 0xbb, 0xbc, 0x45, +0x22, 0x2b, 0xf, 0x20, 0x8, 0x1c, 0x5, 0x1b, 0x6, 0x1e, 0xb, 0x27, +0x15, 0x39, 0x36, 0xcd, 0xa0, 0xac, 0x8f, 0x9f, 0x89, 0x9c, 0x85, 0x9c, +0x85, 0x9e, 0x8a, 0xa5, 0x96, 0xb8, 0xb5, 0x4c, 0x25, 0x2d, 0xf, 0x21, +0x8, 0x1c, 0x5, 0x1b, 0x6, 0x1d, 0xa, 0x26, 0x14, 0x35, 0x30, 0xd9, +0xa4, 0xad, 0x90, 0xa1, 0x89, 0x9d, 0x86, 0x9c, 0x85, 0x9d, 0x8a, 0xa4, +0x94, 0xb3, 0xae, 0x5a, 0x28, 0x2e, 0x11, 0x23, 0x9, 0x1d, 0x5, 0x1b, +0x6, 0x1d, 0xa, 0x24, 0x12, 0x32, 0x2c, 0xfb, 0xa8, 0xb0, 0x91, 0xa2, +0x8a, 0x9d, 0x86, 0x9c, 0x85, 0x9d, 0x8a, 0xa3, 0x93, 0xb0, 0xab, 0x6f, +0x2c, 0x30, 0x13, 0x24, 0xa, 0x1d, 0x6, 0x1b, 0x6, 0x1d, 0xa, 0x24, +0x11, 0x31, 0x28, 0x64, 0xac, 0xb3, 0x93, 0xa3, 0x8a, 0x9d, 0x86, 0x9c, +0x86, 0x9d, 0x89, 0xa2, 0x91, 0xae, 0xa8, 0xeb, 0x2f, 0x32, 0x14, 0x25, +0xa, 0x1e, 0x6, 0x1c, 0x5, 0x1d, 0x9, 0x23, 0x10, 0x2f, 0x25, 0x58, +0xb0, 0xb6, 0x94, 0xa4, 0x8a, 0x9d, 0x86, 0x9c, 0x86, 0x9d, 0x88, 0xa1, +0x8f, 0xad, 0xa5, 0xdc, 0x34, 0x35, 0x16, 0x26, 0xb, 0x1e, 0x6, 0x1c, +0x5, 0x1c, 0x9, 0x22, 0xf, 0x2e, 0x21, 0x4d, 0xba, 0xb9, 0x96, 0xa6, +0x8b, 0x9e, 0x87, 0x9c, 0x85, 0x9d, 0x88, 0xa0, 0x8e, 0xac, 0xa0, 0xcf, +0x3c, 0x38, 0x18, 0x28, 0xc, 0x1f, 0x6, 0x1c, 0x5, 0x1c, 0x8, 0x21, +0xe, 0x2c, 0x1e, 0x46, 0xc5, 0xbd, 0x98, 0xa7, 0x8b, 0x9e, 0x87, 0x9d, +0x85, 0x9d, 0x88, 0x9f, 0x8e, 0xaa, 0x9e, 0xc8, 0x45, 0x3b, 0x19, 0x29, +0xc, 0x1f, 0x7, 0x1c, 0x5, 0x1c, 0x8, 0x20, 0xe, 0x2b, 0x1d, 0x41, +0xcf, 0xbf, 0x99, 0xa8, 0x8c, 0x9f, 0x87, 0x9d, 0x86, 0x9d, 0x88, 0x9f, +0x8d, 0xaa, 0x9d, 0xc4, 0x59, 0x3e, 0x1b, 0x2a, 0xd, 0x20, 0x7, 0x1c, +0x6, 0x1c, 0x8, 0x20, 0xd, 0x2a, 0x1b, 0x3e, 0xf0, 0xc2, 0x9b, 0xa9, +0x8d, 0x9f, 0x88, 0x9d, 0x86, 0x9d, 0x88, 0x9f, 0x8d, 0xa9, 0x9c, 0xc0, +0xe2, 0x40, 0x1d, 0x2b, 0xe, 0x20, 0x8, 0x1c, 0x6, 0x1c, 0x8, 0x1f, +0xd, 0x2a, 0x1a, 0x3d, 0x52, 0xc4, 0x9e, 0xaa, 0x8f, 0x9f, 0x89, 0x9d, +0x87, 0x9d, 0x88, 0x9f, 0x8d, 0xa8, 0x9b, 0xbe, 0xc9, 0x43, 0x20, 0x2b, +0xf, 0x20, 0x9, 0x1c, 0x7, 0x1c, 0x9, 0x1f, 0xd, 0x29, 0x1a, 0x3c, +0x44, 0xc7, 0xa0, 0xab, 0x90, 0xa0, 0x8a, 0x9d, 0x88, 0x9c, 0x89, 0x9f, +0x8e, 0xa8, 0x9a, 0xbc, 0xbe, 0x45, 0x24, 0x2c, 0x12, 0x21, 0xb, 0x1c, +0x8, 0x1c, 0xa, 0x1f, 0xe, 0x28, 0x19, 0x3a, 0x3b, 0xcb, 0xa5, 0xab, +0x93, 0xa0, 0x8c, 0x9d, 0x89, 0x9c, 0x8a, 0x9e, 0x8e, 0xa7, 0x9a, 0xba, +0xb8, 0x4a, 0x29, 0x2c, 0x15, 0x21, 0xc, 0x1c, 0xa, 0x1c, 0xb, 0x1e, +0xe, 0x27, 0x19, 0x38, 0x37, 0xce, 0xaa, 0xac, 0x96, 0xa0, 0x8e, 0x9d, +0x8b, 0x9c, 0x8b, 0x9e, 0x8f, 0xa6, 0x9a, 0xb8, 0xb4, 0x4d, 0x2d, 0x2d, +0x18, 0x21, 0xe, 0x1c, 0xc, 0x1b, 0xc, 0x1e, 0xf, 0x26, 0x1a, 0x36, +0x32, 0xd5, 0xae, 0xad, 0x99, 0xa0, 0x8f, 0x9c, 0x8c, 0x9c, 0x8c, 0x9d, +0x8f, 0xa5, 0x9a, 0xb5, 0xb0, 0x51, 0x31, 0x2d, 0x1b, 0x22, 0x10, 0x1c, +0xd, 0x1b, 0xd, 0x1d, 0x10, 0x25, 0x1a, 0x35, 0x2f, 0xdd, 0xb5, 0xae, +0x9c, 0xa1, 0x92, 0x9c, 0x8e, 0x9c, 0x8e, 0x9d, 0x91, 0xa3, 0x9a, 0xb3, +0xaf, 0x58, 0x39, 0x2e, 0x1e, 0x22, 0x14, 0x1d, 0xf, 0x1b, 0xe, 0x1d, +0x12, 0x24, 0x1b, 0x33, 0x2e, 0xec, 0xbe, 0xaf, 0x9f, 0xa1, 0x95, 0x9c, +0x90, 0x9b, 0x90, 0x9d, 0x93, 0xa2, 0x9b, 0xb0, 0xae, 0x62, 0x40, 0x2f, +0x22, 0x23, 0x18, 0x1d, 0x12, 0x1b, 0x10, 0x1c, 0x14, 0x23, 0x1c, 0x30, +0x2d, 0x6d, 0xcc, 0xb1, 0xa3, 0xa2, 0x98, 0x9c, 0x93, 0x9b, 0x92, 0x9d, +0x94, 0xa1, 0x9b, 0xae, 0xac, 0xe8, 0x4b, 0x31, 0x25, 0x24, 0x1a, 0x1d, +0x14, 0x1b, 0x12, 0x1c, 0x15, 0x21, 0x1c, 0x2e, 0x2b, 0x58, 0xea, 0xb6, +0xa7, 0xa4, 0x9a, 0x9d, 0x95, 0x9b, 0x93, 0x9d, 0x95, 0xa1, 0x9b, 0xac, +0xaa, 0xd2, 0x5d, 0x34, 0x29, 0x25, 0x1c, 0x1e, 0x16, 0x1b, 0x13, 0x1c, +0x15, 0x20, 0x1c, 0x2d, 0x2a, 0x4e, 0x58, 0xba, 0xac, 0xa6, 0x9c, 0x9e, +0x96, 0x9c, 0x95, 0x9d, 0x96, 0xa0, 0x9a, 0xab, 0xa8, 0xca, 0xe9, 0x38, +0x2c, 0x27, 0x1e, 0x1f, 0x17, 0x1c, 0x13, 0x1c, 0x15, 0x1f, 0x1c, 0x2c, +0x28, 0x48, 0x49, 0xbe, 0xaf, 0xa8, 0x9d, 0x9e, 0x97, 0x9c, 0x95, 0x9d, +0x96, 0x9f, 0x9a, 0xa9, 0xa5, 0xc2, 0xcf, 0x3c, 0x2e, 0x28, 0x1f, 0x1f, +0x18, 0x1c, 0x13, 0x1c, 0x15, 0x1f, 0x1b, 0x2a, 0x26, 0x40, 0x3f, 0xc4, +0xb3, 0xaa, 0x9e, 0x9f, 0x97, 0x9c, 0x95, 0x9d, 0x96, 0x9f, 0x99, 0xa8, +0xa3, 0xbc, 0xc6, 0x40, 0x32, 0x2a, 0x20, 0x21, 0x19, 0x1d, 0x14, 0x1c, +0x15, 0x1f, 0x1a, 0x29, 0x24, 0x3c, 0x3b, 0xcd, 0xb8, 0xac, 0x9f, 0xa0, +0x98, 0x9d, 0x96, 0x9d, 0x96, 0x9f, 0x99, 0xa6, 0xa2, 0xb8, 0xbf, 0x49, +0x37, 0x2c, 0x23, 0x22, 0x1a, 0x1d, 0x15, 0x1c, 0x15, 0x1e, 0x1a, 0x28, +0x23, 0x39, 0x36, 0xda, 0xbd, 0xae, 0xa1, 0xa1, 0x99, 0x9d, 0x97, 0x9d, +0x96, 0x9e, 0x99, 0xa5, 0xa0, 0xb5, 0xba, 0x52, 0x3d, 0x2e, 0x25, 0x24, +0x1b, 0x1e, 0x15, 0x1c, 0x15, 0x1e, 0x1a, 0x26, 0x21, 0x35, 0x32, 0xf0, +0xc5, 0xb1, 0xa4, 0xa3, 0x9a, 0x9d, 0x97, 0x9d, 0x96, 0x9e, 0x98, 0xa4, +0x9f, 0xb2, 0xb6, 0x60, 0x43, 0x30, 0x28, 0x25, 0x1c, 0x1e, 0x16, 0x1c, +0x16, 0x1e, 0x1a, 0x25, 0x20, 0x32, 0x2f, 0x61, 0xcf, 0xb4, 0xa6, 0xa4, +0x9c, 0x9e, 0x98, 0x9d, 0x97, 0x9e, 0x98, 0xa3, 0x9e, 0xaf, 0xb1, 0xf3, +0x4c, 0x34, 0x2a, 0x27, 0x1d, 0x1f, 0x17, 0x1c, 0x16, 0x1d, 0x19, 0x24, +0x1f, 0x30, 0x2d, 0x52, 0xe1, 0xb8, 0xa9, 0xa6, 0x9d, 0x9f, 0x98, 0x9d, +0x97, 0x9e, 0x98, 0xa2, 0x9e, 0xae, 0xaf, 0xda, 0x59, 0x37, 0x2c, 0x29, +0x1e, 0x20, 0x18, 0x1d, 0x16, 0x1d, 0x19, 0x24, 0x1e, 0x2f, 0x2b, 0x4a, +0x67, 0xbc, 0xab, 0xa8, 0x9e, 0x9f, 0x99, 0x9e, 0x97, 0x9e, 0x98, 0xa2, +0x9d, 0xac, 0xad, 0xce, 0xf4, 0x3b, 0x2f, 0x2a, 0x1f, 0x21, 0x19, 0x1d, +0x16, 0x1d, 0x19, 0x23, 0x1e, 0x2d, 0x29, 0x45, 0x4f, 0xc0, 0xae, 0xaa, +0x9f, 0xa0, 0x9a, 0x9e, 0x98, 0x9e, 0x98, 0xa1, 0x9d, 0xab, 0xab, 0xc7, +0xd5, 0x3e, 0x34, 0x2c, 0x21, 0x22, 0x1a, 0x1e, 0x17, 0x1d, 0x19, 0x22, +0x1d, 0x2c, 0x27, 0x3f, 0x45, 0xc7, 0xb2, 0xab, 0xa0, 0xa1, 0x9b, 0x9e, +0x98, 0x9e, 0x98, 0xa1, 0x9c, 0xaa, 0xa9, 0xc0, 0xca, 0x43, 0x38, 0x2d, +0x23, 0x24, 0x1a, 0x1e, 0x17, 0x1e, 0x19, 0x22, 0x1d, 0x2b, 0x26, 0x3c, +0x3f, 0xce, 0xb5, 0xad, 0xa2, 0xa3, 0x9c, 0x9f, 0x99, 0x9e, 0x98, 0xa0, +0x9c, 0xa9, 0xa8, 0xbd, 0xc4, 0x49, 0x3c, 0x2f, 0x25, 0x25, 0x1b, 0x1e, +0x18, 0x1e, 0x19, 0x21, 0x1d, 0x2a, 0x25, 0x3a, 0x3c, 0xd8, 0xb9, 0xae, +0xa4, 0xa4, 0x9d, 0x9f, 0x99, 0x9f, 0x98, 0xa0, 0x9c, 0xa8, 0xa7, 0xbb, +0xbf, 0x4e, 0x3f, 0x30, 0x27, 0x26, 0x1c, 0x1f, 0x18, 0x1e, 0x19, 0x21, +0x1d, 0x2a, 0x24, 0x38, 0x39, 0xe7, 0xbd, 0xb0, 0xa6, 0xa5, 0x9d, 0xa0, +0x9a, 0x9f, 0x99, 0xa0, 0x9c, 0xa7, 0xa6, 0xb9, 0xbd, 0x54, 0x45, 0x33, +0x29, 0x28, 0x1d, 0x1f, 0x19, 0x1e, 0x1a, 0x21, 0x1d, 0x2a, 0x24, 0x37, +0x35, 0x70, 0xc4, 0xb3, 0xa7, 0xa5, 0x9e, 0xa0, 0x9b, 0x9f, 0x99, 0xa0, +0x9b, 0xa6, 0xa4, 0xb6, 0xba, 0x5c, 0x4c, 0x35, 0x2c, 0x29, 0x1e, 0x20, +0x1a, 0x1e, 0x1a, 0x20, 0x1d, 0x29, 0x23, 0x35, 0x31, 0x5a, 0xcf, 0xb7, +0xaa, 0xa7, 0x9f, 0xa1, 0x9c, 0xa0, 0x9a, 0xa1, 0x9b, 0xa5, 0xa3, 0xb3, +0xb7, 0x6c, 0x58, 0x37, 0x2f, 0x2b, 0x20, 0x22, 0x1b, 0x1e, 0x1a, 0x20, +0x1d, 0x29, 0x23, 0x33, 0x2f, 0x4e, 0xe7, 0xba, 0xac, 0xa8, 0xa1, 0xa1, +0x9d, 0xa0, 0x9b, 0xa1, 0x9b, 0xa4, 0xa2, 0xb0, 0xb4, 0xee, 0x6b, 0x3a, +0x32, 0x2c, 0x22, 0x23, 0x1b, 0x1e, 0x1b, 0x1f, 0x1d, 0x28, 0x23, 0x31, +0x2d, 0x48, 0x6d, 0xbe, 0xae, 0xa9, 0xa2, 0xa2, 0x9e, 0xa1, 0x9b, 0xa0, +0x9c, 0xa3, 0xa2, 0xae, 0xb2, 0xdc, 0xed, 0x3c, 0x36, 0x2d, 0x24, 0x23, +0x1c, 0x1e, 0x1b, 0x1f, 0x1e, 0x27, 0x22, 0x2f, 0x2c, 0x42, 0x58, 0xc2, +0xb0, 0xaa, 0xa4, 0xa3, 0x9e, 0xa1, 0x9c, 0xa0, 0x9c, 0xa2, 0xa1, 0xad, +0xb0, 0xd0, 0xd8, 0x3f, 0x3a, 0x2e, 0x26, 0x24, 0x1d, 0x1e, 0x1c, 0x1f, +0x1e, 0x26, 0x22, 0x2e, 0x2b, 0x3d, 0x4e, 0xc7, 0xb4, 0xab, 0xa6, 0xa3, +0x9f, 0xa1, 0x9c, 0x9f, 0x9c, 0xa1, 0xa1, 0xab, 0xaf, 0xc9, 0xce, 0x44, +0x3d, 0x30, 0x28, 0x25, 0x1d, 0x1e, 0x1c, 0x1e, 0x1e, 0x25, 0x21, 0x2c, +0x2a, 0x3a, 0x47, 0xce, 0xb8, 0xac, 0xa8, 0xa4, 0xa0, 0xa1, 0x9c, 0x9f, +0x9c, 0xa0, 0xa0, 0xaa, 0xad, 0xc3, 0xc8, 0x4a, 0x42, 0x32, 0x29, 0x26, +0x1e, 0x1e, 0x1c, 0x1e, 0x1e, 0x24, 0x21, 0x2b, 0x29, 0x38, 0x40, 0xd9, +0xbb, 0xae, 0xa9, 0xa5, 0xa1, 0xa1, 0x9d, 0x9f, 0x9c, 0xa0, 0xa0, 0xa9, +0xac, 0xbe, 0xc2, 0x51, 0x49, 0x35, 0x2b, 0x27, 0x1f, 0x1e, 0x1d, 0x1e, +0x1e, 0x23, 0x21, 0x2a, 0x28, 0x34, 0x3d, 0xed, 0xbf, 0xaf, 0xab, 0xa6, +0xa3, 0xa2, 0x9e, 0x9f, 0x9c, 0x9f, 0x9f, 0xa7, 0xab, 0xba, 0xbf, 0x60, +0x4f, 0x38, 0x2d, 0x28, 0x20, 0x1f, 0x1d, 0x1e, 0x1e, 0x22, 0x21, 0x28, +0x28, 0x30, 0x3b, 0x63, 0xc3, 0xb2, 0xad, 0xa7, 0xa4, 0xa2, 0x9e, 0x9f, +0x9d, 0x9f, 0x9f, 0xa6, 0xab, 0xb7, 0xbd, 0xef, 0x59, 0x3c, 0x2f, 0x2a, +0x22, 0x1f, 0x1e, 0x1e, 0x1f, 0x21, 0x21, 0x27, 0x27, 0x2e, 0x39, 0x52, +0xca, 0xb6, 0xae, 0xa9, 0xa6, 0xa3, 0x9f, 0x9f, 0x9d, 0x9e, 0x9f, 0xa4, +0xaa, 0xb3, 0xba, 0xd6, 0x6c, 0x40, 0x31, 0x2b, 0x23, 0x20, 0x1f, 0x1e, +0x1f, 0x21, 0x21, 0x25, 0x26, 0x2c, 0x36, 0x48, 0xd3, 0xba, 0xb0, 0xaa, +0xa7, 0xa4, 0x9f, 0x9f, 0x9d, 0x9e, 0x9f, 0xa3, 0xa9, 0xaf, 0xb7, 0xca, +0xe7, 0x49, 0x35, 0x2d, 0x25, 0x21, 0x1f, 0x1e, 0x1f, 0x20, 0x20, 0x24, +0x26, 0x2a, 0x33, 0x3f, 0xe0, 0xbe, 0xb3, 0xac, 0xa9, 0xa5, 0xa0, 0x9f, +0x9e, 0x9e, 0x9f, 0xa1, 0xa8, 0xad, 0xb5, 0xc1, 0xd7, 0x54, 0x38, 0x2f, +0x26, 0x22, 0x20, 0x1e, 0x1f, 0x1f, 0x20, 0x23, 0x25, 0x28, 0x30, 0x3b, +0x7e, 0xc6, 0xb7, 0xae, 0xaa, 0xa7, 0xa2, 0x9f, 0x9e, 0x9d, 0x9f, 0xa0, +0xa8, 0xab, 0xb3, 0xbc, 0xce, 0x69, 0x3c, 0x31, 0x28, 0x23, 0x21, 0x1f, +0x20, 0x1f, 0x21, 0x22, 0x24, 0x26, 0x2f, 0x36, 0x5f, 0xce, 0xb9, 0xaf, +0xac, 0xa8, 0xa3, 0xa0, 0x9e, 0x9d, 0x9f, 0x9f, 0xa7, 0xaa, 0xb1, 0xb8, +0xc9, 0xe6, 0x3f, 0x36, 0x2a, 0x25, 0x22, 0x1f, 0x21, 0x1f, 0x21, 0x21, +0x24, 0x25, 0x2e, 0x32, 0x53, 0xdf, 0xbc, 0xb3, 0xad, 0xa9, 0xa5, 0xa1, +0x9f, 0x9d, 0x9f, 0x9f, 0xa7, 0xa8, 0xb0, 0xb5, 0xc5, 0xd3, 0x46, 0x3a, +0x2b, 0x26, 0x23, 0x1f, 0x21, 0x1f, 0x22, 0x21, 0x24, 0x24, 0x2d, 0x2e, +0x4b, 0x69, 0xbf, 0xb6, 0xae, 0xaa, 0xa6, 0xa2, 0x9f, 0x9e, 0x9f, 0x9e, +0xa6, 0xa6, 0xaf, 0xb2, 0xc0, 0xca, 0x4d, 0x3f, 0x2d, 0x29, 0x24, 0x20, +0x22, 0x1f, 0x22, 0x20, 0x24, 0x23, 0x2b, 0x2c, 0x43, 0x51, 0xc4, 0xba, +0xb0, 0xac, 0xa8, 0xa4, 0xa0, 0x9e, 0x9f, 0x9e, 0xa5, 0xa5, 0xae, 0xaf, +0xbd, 0xc2, 0x5a, 0x48, 0x2f, 0x2b, 0x25, 0x21, 0x22, 0x1f, 0x23, 0x20, +0x24, 0x22, 0x2a, 0x2b, 0x3e, 0x46, 0xca, 0xbf, 0xb3, 0xae, 0xa9, 0xa5, +0xa2, 0x9e, 0x9f, 0x9e, 0xa5, 0xa4, 0xad, 0xad, 0xbb, 0xbd, 0x6f, 0x52, +0x33, 0x2d, 0x27, 0x23, 0x23, 0x20, 0x23, 0x20, 0x24, 0x21, 0x29, 0x29, +0x3b, 0x3e, 0xd0, 0xc6, 0xb5, 0xb0, 0xab, 0xa7, 0xa3, 0x9f, 0xa0, 0x9e, +0xa4, 0xa3, 0xad, 0xac, 0xb9, 0xb9, 0xe8, 0x67, 0x36, 0x2f, 0x28, 0x24, +0x24, 0x20, 0x23, 0x20, 0x24, 0x20, 0x29, 0x27, 0x39, 0x3a, 0xdc, 0xcf, +0xb8, 0xb4, 0xac, 0xa8, 0xa4, 0x9f, 0xa0, 0x9e, 0xa4, 0xa2, 0xac, 0xaa, +0xb7, 0xb5, 0xd9, 0xe7, 0x39, 0x32, 0x29, 0x25, 0x25, 0x21, 0x24, 0x20, +0x24, 0x1f, 0x28, 0x26, 0x37, 0x37, 0xf3, 0xe0, 0xbc, 0xb8, 0xad, 0xaa, +0xa5, 0xa0, 0xa1, 0x9e, 0xa4, 0xa1, 0xab, 0xa9, 0xb5, 0xb1, 0xcf, 0xd3, +0x3d, 0x36, 0x2b, 0x27, 0x26, 0x22, 0x24, 0x20, 0x24, 0x1f, 0x28, 0x25, +0x34, 0x33, 0x64, 0x6d, 0xbf, 0xbc, 0xaf, 0xab, 0xa6, 0xa1, 0xa1, 0x9e, +0xa4, 0xa1, 0xab, 0xa7, 0xb3, 0xaf, 0xc9, 0xca, 0x40, 0x3a, 0x2c, 0x29, +0x27, 0x23, 0x25, 0x20, 0x24, 0x1f, 0x27, 0x24, 0x32, 0x30, 0x56, 0x58, +0xc3, 0xbf, 0xb1, 0xad, 0xa7, 0xa2, 0xa2, 0x9e, 0xa4, 0xa0, 0xaa, 0xa7, +0xb1, 0xae, 0xc5, 0xc3, 0x46, 0x3d, 0x2e, 0x2a, 0x28, 0x24, 0x26, 0x21, +0x25, 0x1f, 0x27, 0x23, 0x31, 0x2e, 0x4e, 0x4d, 0xc8, 0xc4, 0xb3, 0xae, +0xa9, 0xa3, 0xa3, 0x9f, 0xa5, 0xa0, 0xaa, 0xa6, 0xb0, 0xac, 0xc1, 0xbe, +0x4b, 0x43, 0x2f, 0x2c, 0x29, 0x25, 0x27, 0x21, 0x25, 0x1f, 0x27, 0x22, +0x2f, 0x2d, 0x49, 0x46, 0xce, 0xcb, 0xb6, 0xb0, 0xaa, 0xa4, 0xa4, 0x9f, +0xa5, 0x9f, 0xaa, 0xa5, 0xaf, 0xab, 0xbd, 0xbb, 0x55, 0x4b, 0x32, 0x2e, +0x2b, 0x26, 0x27, 0x21, 0x25, 0x1f, 0x27, 0x21, 0x2e, 0x2b, 0x43, 0x3f, +0xd9, 0xd6, 0xba, 0xb3, 0xab, 0xa6, 0xa5, 0x9f, 0xa5, 0x9f, 0xa9, 0xa4, +0xae, 0xaa, 0xbb, 0xb8, 0x65, 0x56, 0x36, 0x2f, 0x2c, 0x27, 0x28, 0x22, +0x26, 0x1f, 0x27, 0x21, 0x2d, 0x2a, 0x3f, 0x3b, 0xea, 0xe8, 0xbd, 0xb6, +0xad, 0xa7, 0xa6, 0xa0, 0xa6, 0x9f, 0xa9, 0xa3, 0xae, 0xa8, 0xb9, 0xb4, +0xf9, 0x67, 0x39, 0x32, 0x2d, 0x29, 0x29, 0x23, 0x26, 0x1f, 0x27, 0x20, +0x2d, 0x28, 0x3d, 0x38, 0x72, 0x6a, 0xbf, 0xb9, 0xae, 0xa8, 0xa7, 0xa0, +0xa6, 0x9f, 0xa9, 0xa2, 0xad, 0xa7, 0xb7, 0xb1, 0xdf, 0xe8, 0x3c, 0x36, +0x2f, 0x2a, 0x2a, 0x23, 0x27, 0x1f, 0x27, 0x1f, 0x2c, 0x27, 0x3b, 0x34, +0x5d, 0x55, 0xc5, 0xbc, 0xb0, 0xa9, 0xa8, 0xa1, 0xa7, 0x9f, 0xa9, 0xa1, +0xac, 0xa6, 0xb5, 0xae, 0xd3, 0xd4, 0x3f, 0x3a, 0x30, 0x2b, 0x2b, 0x24, +0x28, 0x1f, 0x27, 0x1f, 0x2c, 0x26, 0x38, 0x30, 0x53, 0x4b, 0xca, 0xc1, +0xb3, 0xab, 0xa9, 0xa2, 0xa7, 0x9f, 0xa9, 0xa1, 0xac, 0xa5, 0xb3, 0xad, +0xcb, 0xc9, 0x45, 0x3d, 0x32, 0x2c, 0x2c, 0x25, 0x28, 0x1f, 0x27, 0x1f, +0x2b, 0x24, 0x36, 0x2e, 0x4d, 0x46, 0xcf, 0xc7, 0xb6, 0xad, 0xab, 0xa3, +0xa8, 0x9f, 0xa9, 0xa0, 0xac, 0xa4, 0xb2, 0xac, 0xc6, 0xc1, 0x4b, 0x43, +0x35, 0x2d, 0x2d, 0x25, 0x29, 0x20, 0x28, 0x1f, 0x2a, 0x23, 0x34, 0x2c, +0x4a, 0x40, 0xd8, 0xcd, 0xb9, 0xaf, 0xac, 0xa4, 0xa8, 0x9f, 0xa9, 0x9f, +0xac, 0xa3, 0xb1, 0xaa, 0xc1, 0xbc, 0x53, 0x4b, 0x37, 0x2e, 0x2e, 0x26, +0x2a, 0x20, 0x28, 0x1f, 0x2a, 0x21, 0x33, 0x2a, 0x46, 0x3c, 0xe2, 0xd9, +0xbc, 0xb2, 0xae, 0xa6, 0xa9, 0x9f, 0xa9, 0x9f, 0xac, 0xa2, 0xb0, 0xa9, +0xbe, 0xb7, 0x5f, 0x5b, 0x3a, 0x31, 0x2f, 0x27, 0x2c, 0x21, 0x29, 0x1f, +0x2a, 0x20, 0x31, 0x28, 0x42, 0x38, 0xfc, 0xfb, 0xbf, 0xb7, 0xaf, 0xa7, +0xaa, 0x9f, 0xaa, 0x9f, 0xac, 0xa2, 0xaf, 0xa7, 0xbb, 0xb2, 0x7a, 0xf6, +0x3c, 0x34, 0x31, 0x29, 0x2d, 0x22, 0x29, 0x1f, 0x2a, 0x1f, 0x30, 0x27, +0x3f, 0x34, 0x65, 0x5b, 0xc5, 0xbb, 0xb1, 0xa9, 0xab, 0xa0, 0xaa, 0x9f, +0xac, 0xa1, 0xaf, 0xa6, 0xb9, 0xaf, 0xe4, 0xd9, 0x3f, 0x38, 0x33, 0x2a, +0x2d, 0x23, 0x2a, 0x1f, 0x2a, 0x1f, 0x2f, 0x25, 0x3d, 0x30, 0x59, 0x4d, +0xca, 0xbe, 0xb4, 0xaa, 0xac, 0xa1, 0xaa, 0x9f, 0xac, 0xa0, 0xae, 0xa4, +0xb8, 0xad, 0xd7, 0xcb, 0x44, 0x3c, 0x36, 0x2c, 0x2e, 0x24, 0x2a, 0x1f, +0x2a, 0x1e, 0x2e, 0x24, 0x3b, 0x2e, 0x50, 0x44, 0xcf, 0xc6, 0xb6, 0xac, +0xad, 0xa2, 0xab, 0x9f, 0xac, 0x9f, 0xae, 0xa3, 0xb6, 0xab, 0xcf, 0xc1, +0x49, 0x42, 0x38, 0x2d, 0x2f, 0x25, 0x2b, 0x1f, 0x2a, 0x1e, 0x2e, 0x22, +0x39, 0x2c, 0x4c, 0x3d, 0xd6, 0xcf, 0xb8, 0xae, 0xae, 0xa3, 0xac, 0x9f, +0xac, 0x9f, 0xae, 0xa1, 0xb5, 0xa9, 0xcb, 0xbc, 0x4d, 0x4b, 0x3a, 0x2f, +0x31, 0x26, 0x2c, 0x1f, 0x2a, 0x1e, 0x2e, 0x21, 0x38, 0x2a, 0x49, 0x39, +0xdf, 0xe0, 0xbb, 0xb0, 0xaf, 0xa5, 0xac, 0x9f, 0xad, 0x9f, 0xae, 0xa0, +0xb4, 0xa7, 0xc7, 0xb8, 0x54, 0x58, 0x3c, 0x33, 0x33, 0x28, 0x2d, 0x20, +0x2b, 0x1e, 0x2e, 0x20, 0x37, 0x29, 0x45, 0x35, 0xef, 0x6d, 0xbe, 0xb4, +0xb0, 0xa6, 0xad, 0xa0, 0xad, 0x9f, 0xae, 0xa0, 0xb3, 0xa6, 0xc4, 0xb4, +0x5e, 0x7a, 0x3f, 0x37, 0x35, 0x29, 0x2d, 0x20, 0x2b, 0x1e, 0x2e, 0x1f, +0x36, 0x27, 0x42, 0x31, 0x6e, 0x54, 0xc0, 0xb9, 0xb2, 0xa8, 0xae, 0xa1, +0xad, 0x9f, 0xae, 0x9f, 0xb2, 0xa4, 0xc0, 0xaf, 0x6e, 0xda, 0x42, 0x3b, +0x37, 0x2b, 0x2e, 0x22, 0x2c, 0x1e, 0x2e, 0x1f, 0x35, 0x25, 0x3f, 0x2e, +0x5f, 0x48, 0xc5, 0xbd, 0xb4, 0xaa, 0xaf, 0xa2, 0xae, 0x9f, 0xae, 0x9f, +0xb1, 0xa3, 0xbe, 0xad, 0xee, 0xca, 0x47, 0x40, 0x39, 0x2d, 0x2f, 0x23, +0x2c, 0x1e, 0x2e, 0x1f, 0x34, 0x24, 0x3e, 0x2c, 0x57, 0x3f, 0xc9, 0xc5, +0xb7, 0xac, 0xaf, 0xa3, 0xae, 0x9f, 0xae, 0x9f, 0xb1, 0xa1, 0xbd, 0xab, +0xde, 0xc1, 0x4b, 0x49, 0x3b, 0x2f, 0x30, 0x25, 0x2d, 0x1f, 0x2e, 0x1e, +0x33, 0x23, 0x3c, 0x2b, 0x50, 0x3b, 0xcd, 0xcf, 0xb9, 0xae, 0xb1, 0xa5, +0xae, 0xa0, 0xae, 0x9f, 0xb0, 0xa0, 0xbb, 0xa9, 0xd7, 0xbc, 0x4f, 0x53, +0x3c, 0x32, 0x32, 0x26, 0x2d, 0x1f, 0x2e, 0x1e, 0x33, 0x21, 0x3b, 0x29, +0x4d, 0x37, 0xd4, 0xe1, 0xbb, 0xb0, 0xb2, 0xa6, 0xaf, 0xa1, 0xae, 0x9f, +0xb0, 0x9f, 0xba, 0xa7, 0xcf, 0xb8, 0x57, 0x69, 0x3e, 0x36, 0x34, 0x28, +0x2e, 0x1f, 0x2e, 0x1e, 0x32, 0x20, 0x3a, 0x27, 0x49, 0x32, 0xdd, 0x65, +0xbd, 0xb5, 0xb4, 0xa8, 0xaf, 0xa1, 0xaf, 0x9f, 0xb0, 0x9f, 0xb9, 0xa5, +0xcc, 0xb3, 0x5e, 0xe2, 0x41, 0x3b, 0x36, 0x2a, 0x2f, 0x20, 0x2e, 0x1e, +0x32, 0x20, 0x39, 0x26, 0x47, 0x2f, 0xec, 0x4e, 0xbf, 0xb9, 0xb5, 0xa9, +0xb1, 0xa3, 0xaf, 0x9f, 0xb0, 0x9f, 0xb7, 0xa4, 0xc8, 0xaf, 0x69, 0xd1, +0x45, 0x3f, 0x38, 0x2c, 0x30, 0x22, 0x2e, 0x1e, 0x32, 0x20, 0x39, 0x26, +0x44, 0x2d, 0x72, 0x44, 0xc4, 0xbe, 0xb7, 0xab, 0xb2, 0xa4, 0xb0, 0xa0, +0xb0, 0x9f, 0xb6, 0xa3, 0xc5, 0xae, 0x7b, 0xca, 0x48, 0x47, 0x3a, 0x2f, +0x31, 0x23, 0x2f, 0x1e, 0x31, 0x1f, 0x38, 0x25, 0x41, 0x2c, 0x5f, 0x3d, +0xc8, 0xc5, 0xb9, 0xac, 0xb3, 0xa6, 0xb1, 0xa1, 0xb1, 0x9f, 0xb5, 0xa1, +0xc2, 0xac, 0xed, 0xc3, 0x4c, 0x50, 0x3d, 0x33, 0x33, 0x25, 0x2f, 0x1f, +0x31, 0x1f, 0x38, 0x24, 0x3f, 0x2a, 0x57, 0x38, 0xcd, 0xcf, 0xba, 0xae, +0xb4, 0xa7, 0xb2, 0xa3, 0xb1, 0x9f, 0xb5, 0xa0, 0xbf, 0xaa, 0xe1, 0xbd, +0x50, 0x68, 0x3f, 0x38, 0x35, 0x27, 0x2f, 0x1f, 0x31, 0x20, 0x38, 0x24, +0x3e, 0x28, 0x4f, 0x33, 0xd2, 0xe6, 0xbc, 0xb2, 0xb6, 0xa9, 0xb3, 0xa4, +0xb1, 0x9f, 0xb4, 0xa0, 0xbe, 0xa9, 0xda, 0xb9, 0x57, 0xe1, 0x41, 0x3c, +0x36, 0x29, 0x30, 0x20, 0x32, 0x20, 0x37, 0x23, 0x3d, 0x27, 0x4d, 0x30, +0xda, 0x65, 0xbe, 0xb6, 0xb7, 0xab, 0xb4, 0xa5, 0xb2, 0x9f, 0xb4, 0x9f, +0xbd, 0xa8, 0xd4, 0xb6, 0x5e, 0xcf, 0x45, 0x41, 0x38, 0x2b, 0x31, 0x21, +0x32, 0x20, 0x37, 0x23, 0x3d, 0x26, 0x4a, 0x2e, 0xe2, 0x53, 0xc0, 0xba, +0xb9, 0xad, 0xb5, 0xa6, 0xb2, 0xa0, 0xb4, 0x9f, 0xbc, 0xa7, 0xcf, 0xb2, +0x68, 0xc7, 0x48, 0x49, 0x3a, 0x2c, 0x33, 0x23, 0x32, 0x21, 0x37, 0x22, +0x3c, 0x25, 0x47, 0x2c, 0xf1, 0x49, 0xc4, 0xbf, 0xba, 0xaf, 0xb6, 0xa7, +0xb3, 0xa0, 0xb4, 0x9f, 0xbb, 0xa6, 0xcc, 0xaf, 0x7c, 0xc0, 0x4b, 0x52, +0x3b, 0x2e, 0x34, 0x25, 0x33, 0x22, 0x36, 0x22, 0x3b, 0x24, 0x45, 0x2b, +0x72, 0x41, 0xc8, 0xc6, 0xbc, 0xb1, 0xb7, 0xa9, 0xb4, 0xa1, 0xb4, 0x9f, +0xba, 0xa5, 0xc9, 0xae, 0xec, 0xbc, 0x4f, 0x63, 0x3d, 0x31, 0x35, 0x26, +0x34, 0x23, 0x36, 0x22, 0x3a, 0x24, 0x43, 0x2a, 0x62, 0x3d, 0xcb, 0xce, +0xbe, 0xb5, 0xb9, 0xaa, 0xb5, 0xa2, 0xb4, 0xa0, 0xba, 0xa5, 0xc6, 0xac, +0xe0, 0xb9, 0x55, 0xed, 0x3f, 0x35, 0x37, 0x28, 0x34, 0x24, 0x36, 0x23, +0x3a, 0x23, 0x40, 0x29, 0x5b, 0x3a, 0xcf, 0xdd, 0xbf, 0xb9, 0xba, 0xac, +0xb5, 0xa3, 0xb4, 0xa0, 0xb9, 0xa4, 0xc4, 0xab, 0xd9, 0xb6, 0x5c, 0xd8, +0x42, 0x39, 0x38, 0x2a, 0x35, 0x25, 0x37, 0x23, 0x39, 0x23, 0x3f, 0x28, +0x55, 0x36, 0xd6, 0x7b, 0xc2, 0xbc, 0xbb, 0xad, 0xb6, 0xa5, 0xb5, 0xa0, +0xb9, 0xa3, 0xc2, 0xaa, 0xd4, 0xb3, 0x64, 0xcc, 0x45, 0x3d, 0x3a, 0x2b, +0x36, 0x26, 0x37, 0x23, 0x39, 0x23, 0x3e, 0x27, 0x4f, 0x33, 0xdd, 0x59, +0xc6, 0xc1, 0xbc, 0xaf, 0xb7, 0xa6, 0xb5, 0xa1, 0xb8, 0xa3, 0xc0, 0xa9, +0xcf, 0xb0, 0x72, 0xc5, 0x48, 0x44, 0x3b, 0x2d, 0x37, 0x27, 0x37, 0x24, +0x39, 0x23, 0x3e, 0x26, 0x4d, 0x30, 0xe7, 0x4d, 0xc9, 0xc8, 0xbe, 0xb2, +0xb8, 0xa7, 0xb6, 0xa2, 0xb8, 0xa3, 0xbf, 0xa8, 0xcd, 0xae, 0xf8, 0xbf, +0x4b, 0x4b, 0x3d, 0x2f, 0x38, 0x28, 0x38, 0x24, 0x39, 0x23, 0x3d, 0x25, +0x4b, 0x2e, 0xf9, 0x45, 0xcc, 0xcf, 0xbf, 0xb5, 0xb9, 0xa8, 0xb6, 0xa2, +0xb8, 0xa3, 0xbe, 0xa7, 0xca, 0xad, 0xe8, 0xbb, 0x4f, 0x55, 0x3e, 0x32, +0x39, 0x29, 0x38, 0x25, 0x39, 0x22, 0x3c, 0x24, 0x48, 0x2c, 0x6e, 0x3f, +0xcf, 0xdd, 0xc2, 0xb8, 0xbb, 0xaa, 0xb7, 0xa3, 0xb8, 0xa2, 0xbd, 0xa6, +0xc8, 0xac, 0xde, 0xb8, 0x55, 0x6f, 0x40, 0x35, 0x3a, 0x2a, 0x39, 0x26, +0x39, 0x23, 0x3c, 0x23, 0x46, 0x2b, 0x62, 0x3b, 0xd4, 0xfa, 0xc4, 0xbc, +0xbc, 0xac, 0xb8, 0xa4, 0xb8, 0xa2, 0xbd, 0xa5, 0xc7, 0xab, 0xd9, 0xb4, +0x5c, 0xdc, 0x44, 0x39, 0x3b, 0x2b, 0x39, 0x26, 0x3a, 0x23, 0x3c, 0x23, +0x43, 0x29, 0x5b, 0x37, 0xd9, 0x64, 0xc7, 0xbf, 0xbe, 0xad, 0xb9, 0xa5, +0xb8, 0xa2, 0xbc, 0xa5, 0xc6, 0xaa, 0xd5, 0xb1, 0x67, 0xcd, 0x47, 0x3c, +0x3c, 0x2c, 0x3a, 0x27, 0x3a, 0x24, 0x3b, 0x23, 0x41, 0x27, 0x56, 0x34, +0xdd, 0x57, 0xca, 0xc5, 0xbf, 0xaf, 0xba, 0xa6, 0xb8, 0xa2, 0xbc, 0xa4, +0xc5, 0xa9, 0xd0, 0xaf, 0x78, 0xc5, 0x4a, 0x41, 0x3d, 0x2d, 0x3b, 0x28, +0x3b, 0x24, 0x3b, 0x22, 0x3f, 0x26, 0x51, 0x31, 0xe5, 0x4d, 0xcc, 0xcc, +0xc1, 0xb3, 0xbb, 0xa6, 0xb8, 0xa2, 0xbc, 0xa4, 0xc4, 0xa8, 0xce, 0xad, +0xee, 0xbe, 0x4d, 0x49, 0x3e, 0x2f, 0x3c, 0x29, 0x3b, 0x25, 0x3b, 0x22, +0x3e, 0x25, 0x4e, 0x2f, 0xef, 0x46, 0xcf, 0xd8, 0xc4, 0xb6, 0xbc, 0xa8, +0xb9, 0xa2, 0xbc, 0xa4, 0xc2, 0xa7, 0xcc, 0xac, 0xe4, 0xba, 0x4f, 0x50, +0x40, 0x31, 0x3c, 0x2a, 0x3c, 0x25, 0x3b, 0x22, 0x3e, 0x24, 0x4c, 0x2d, +0x7c, 0x3f, 0xd4, 0xed, 0xc7, 0xb9, 0xbd, 0xa9, 0xba, 0xa2, 0xbc, 0xa2, +0xc2, 0xa5, 0xcb, 0xaa, 0xdd, 0xb5, 0x56, 0x67, 0x44, 0x35, 0x3e, 0x2a, +0x3d, 0x24, 0x3c, 0x20, 0x3e, 0x21, 0x4b, 0x2a, 0x6b, 0x38, 0xdb, 0x5f, +0xcb, 0xbb, 0xbf, 0xa9, 0xbb, 0xa1, 0xbd, 0xa0, 0xc2, 0xa3, 0xca, 0xa7, +0xda, 0xb0, 0x5d, 0xde, 0x48, 0x38, 0x41, 0x2a, 0x3e, 0x23, 0x3d, 0x1f, +0x3f, 0x1f, 0x4a, 0x26, 0x61, 0x32, 0xe2, 0x4e, 0xce, 0xbe, 0xc2, 0xaa, +0xbd, 0xa1, 0xbe, 0x9f, 0xc3, 0xa0, 0xca, 0xa4, 0xd7, 0xad, 0x67, 0xcc, +0x4c, 0x3b, 0x44, 0x2b, 0x40, 0x22, 0x3f, 0x1e, 0x40, 0x1e, 0x4a, 0x23, +0x5c, 0x2e, 0xec, 0x45, 0xd2, 0xc3, 0xc6, 0xab, 0xbf, 0xa0, 0xbf, 0x9e, +0xc4, 0x9e, 0xca, 0xa1, 0xd5, 0xaa, 0x74, 0xc2, 0x4f, 0x3f, 0x48, 0x2b, +0x43, 0x22, 0x40, 0x1d, 0x42, 0x1d, 0x49, 0x20, 0x59, 0x2b, 0xfb, 0x3e, +0xd8, 0xc9, 0xc9, 0xab, 0xc2, 0xa0, 0xc1, 0x9d, 0xc5, 0x9d, 0xca, 0x9f, +0xd3, 0xa7, 0xf9, 0xbc, 0x55, 0x43, 0x4b, 0x2c, 0x46, 0x22, 0x43, 0x1d, +0x43, 0x1c, 0x49, 0x1f, 0x57, 0x29, 0x75, 0x3a, 0xdd, 0xd0, 0xcc, 0xac, +0xc5, 0x9f, 0xc3, 0x9d, 0xc6, 0x9c, 0xca, 0x9e, 0xd2, 0xa5, 0xed, 0xb8, +0x5b, 0x49, 0x4d, 0x2d, 0x48, 0x22, 0x45, 0x1c, 0x44, 0x1b, 0x4a, 0x1e, +0x55, 0x26, 0x6b, 0x35, 0xe3, 0xdf, 0xcf, 0xad, 0xc7, 0x9f, 0xc5, 0x9c, +0xc7, 0x9c, 0xca, 0x9d, 0xd0, 0xa3, 0xe5, 0xb4, 0x5f, 0x50, 0x50, 0x2e, +0x4b, 0x22, 0x46, 0x1c, 0x45, 0x1a, 0x49, 0x1d, 0x53, 0x24, 0x64, 0x31, +0xeb, 0x73, 0xd3, 0xae, 0xca, 0xa0, 0xc7, 0x9c, 0xc7, 0x9b, 0xca, 0x9c, +0xcf, 0xa0, 0xe0, 0xb0, 0x67, 0x5f, 0x54, 0x2f, 0x4c, 0x23, 0x48, 0x1c, +0x46, 0x1a, 0x49, 0x1c, 0x50, 0x22, 0x5f, 0x2e, 0xf5, 0x5a, 0xd7, 0xb0, +0xcb, 0xa1, 0xc8, 0x9c, 0xc8, 0x9b, 0xc9, 0x9b, 0xce, 0x9f, 0xdd, 0xad, +0x6f, 0xef, 0x58, 0x32, 0x4e, 0x24, 0x49, 0x1c, 0x46, 0x19, 0x49, 0x1b, +0x4f, 0x21, 0x5c, 0x2c, 0x7e, 0x4d, 0xda, 0xb3, 0xcd, 0xa1, 0xc8, 0x9c, +0xc8, 0x9b, 0xc9, 0x9b, 0xcd, 0x9e, 0xd9, 0xac, 0x7b, 0xda, 0x5a, 0x35, +0x4e, 0x25, 0x49, 0x1d, 0x46, 0x1a, 0x48, 0x1b, 0x4d, 0x20, 0x59, 0x2b, +0x74, 0x46, 0xdc, 0xb7, 0xcd, 0xa3, 0xc8, 0x9d, 0xdf, 0x9b, 0xdf, 0x9b, +0xe3, 0x9e, 0xeb, 0xaa, 0xfe, 0xce, 0x6e, 0x39, 0x66, 0x27, 0x5f, 0x1d, +0x5d, 0x1a, 0x5e, 0x1b, 0x63, 0x1f, 0x6b, 0x2a, 0x79, 0x3f, 0xef, 0xbb, +0xe5, 0xa5, 0xdf, 0x9e, 0xde, 0x9c, 0xde, 0x9b, 0xe1, 0x9e, 0xea, 0xa9, +0xfb, 0xc6, 0x6f, 0x3d, 0x67, 0x29, 0x5f, 0x1e, 0x5d, 0x1b, 0x5e, 0x1b, +0x62, 0x1f, 0x6a, 0x29, 0x76, 0x3c, 0xf2, 0xc1, 0xe5, 0xa8, 0xdf, 0x9f, +0xde, 0x9d, 0xde, 0x9c, 0xdf, 0x9e, 0xe8, 0xa8, 0xf9, 0xbf, 0x72, 0x44, +0x67, 0x2c, 0x5f, 0x20, 0x5d, 0x1c, 0x5d, 0x1c, 0x61, 0x1f, 0x68, 0x28, +0x73, 0x39, 0xf4, 0xc9, 0xe6, 0xab, 0xdf, 0xa0, 0xdd, 0x9e, 0xdd, 0x9d, +0xdf, 0x9e, 0xe6, 0xa8, 0xf6, 0xbc, 0x74, 0x4b, 0x68, 0x2e, 0x60, 0x22, +0x5d, 0x1d, 0x5d, 0x1d, 0x5f, 0x20, 0x67, 0x28, 0x71, 0x37, 0xf7, 0xd3, +0xe7, 0xad, 0xdf, 0xa2, 0xdd, 0x9e, 0xdd, 0x9d, 0xde, 0x9f, 0xe5, 0xa7, +0xf2, 0xba, 0x76, 0x52, 0x69, 0x31, 0x60, 0x25, 0x5c, 0x1e, 0x5c, 0x1d, +0x5f, 0x20, 0x66, 0x28, 0x6f, 0x35, 0xfa, 0xe4, 0xe8, 0xaf, 0xdf, 0xa4, +0xdd, 0x9f, 0xdd, 0x9e, 0xde, 0x9f, 0xe3, 0xa7, 0xef, 0xb8, 0x78, 0x5e, +0x6a, 0x34, 0x61, 0x27, 0x5d, 0x1f, 0x5c, 0x1e, 0x5e, 0x21, 0x64, 0x29, +0x6d, 0x34, 0xfd, 0x6f, 0xe9, 0xb3, 0xdf, 0xa6, 0xdd, 0xa1, 0xdd, 0x9f, +0xdd, 0xa0, 0xe1, 0xa7, 0xed, 0xb6, 0x7a, 0x6f, 0x6a, 0x38, 0x62, 0x2a, +0x5d, 0x21, 0x5b, 0x1f, 0x5d, 0x22, 0x63, 0x29, 0x6c, 0x33, 0x7e, 0x5a, +0xeb, 0xb7, 0xdf, 0xa8, 0xdd, 0xa3, 0xdc, 0xa1, 0xdd, 0xa1, 0xe0, 0xa7, +0xec, 0xb5, 0x7c, 0xee, 0x6b, 0x3b, 0x63, 0x2c, 0x5d, 0x23, 0x5b, 0x1f, +0x5d, 0x23, 0x62, 0x29, 0x6b, 0x33, 0x7b, 0x51, 0xec, 0xba, 0xe0, 0xaa, +0xdd, 0xa5, 0xdc, 0xa2, 0xdd, 0xa2, 0xdf, 0xa7, 0xea, 0xb4, 0x7e, 0xde, +0x6d, 0x3f, 0x64, 0x2e, 0x5d, 0x25, 0x5b, 0x21, 0x5c, 0x24, 0x61, 0x2a, +0x69, 0x32, 0x78, 0x4c, 0xed, 0xbe, 0xe1, 0xac, 0xdd, 0xa7, 0xdc, 0xa4, +0xdc, 0xa3, 0xde, 0xa8, 0xe9, 0xb4, 0xfe, 0xd5, 0x6e, 0x44, 0x65, 0x2f, +0x5d, 0x27, 0x5b, 0x23, 0x5c, 0x25, 0x60, 0x2a, 0x68, 0x31, 0x75, 0x49, +0xee, 0xc3, 0xe2, 0xae, 0xdd, 0xa9, 0xdc, 0xa6, 0xdc, 0xa5, 0xde, 0xa9, +0xe8, 0xb3, 0xfb, 0xce, 0x6f, 0x4a, 0x66, 0x33, 0x5e, 0x29, 0x5b, 0x25, +0x5c, 0x26, 0x5f, 0x2b, 0x67, 0x31, 0x73, 0x46, 0xf0, 0xc9, 0xe3, 0xb1, +0xde, 0xab, 0xdc, 0xa8, 0xdc, 0xa6, 0xde, 0xa9, 0xe7, 0xb3, 0xf8, 0xcb, +0x72, 0x50, 0x67, 0x37, 0x5e, 0x2b, 0x5b, 0x27, 0x5c, 0x28, 0x5f, 0x2b, +0x66, 0x31, 0x70, 0x43, 0xf3, 0xce, 0xe4, 0xb5, 0xde, 0xad, 0xdd, 0xa9, +0xdc, 0xa7, 0xdd, 0xaa, 0xe5, 0xb3, 0xf5, 0xc8, 0x75, 0x5a, 0x68, 0x3a, +0x5e, 0x2d, 0x5b, 0x28, 0x5c, 0x29, 0x5f, 0x2c, 0x65, 0x31, 0x6e, 0x41, +0xf5, 0xd7, 0xe5, 0xb8, 0xdf, 0xae, 0xdd, 0xab, 0xdc, 0xa9, 0xdd, 0xab, +0xe4, 0xb3, 0xf3, 0xc5, 0x77, 0x65, 0x69, 0x3d, 0x5f, 0x2e, 0x5b, 0x2a, +0x5c, 0x2a, 0x5e, 0x2c, 0x64, 0x31, 0x6d, 0x3f, 0xf8, 0xe1, 0xe7, 0xbb, +0xdf, 0xb0, 0xdd, 0xac, 0xdc, 0xaa, 0xdd, 0xab, 0xe3, 0xb3, 0xef, 0xc3, +0x7a, 0x7a, 0x6a, 0x3f, 0x5f, 0x30, 0x5c, 0x2b, 0x5c, 0x2b, 0x5e, 0x2d, +0x63, 0x32, 0x6c, 0x3e, 0xfb, 0xf4, 0xe8, 0xbe, 0xe0, 0xb3, 0xdd, 0xad, +0xdc, 0xab, 0xdd, 0xac, 0xe3, 0xb3, 0xee, 0xc1, 0x7d, 0xf0, 0x6c, 0x43, +0x60, 0x33, 0x5c, 0x2d, 0x5c, 0x2c, 0x5e, 0x2e, 0x62, 0x33, 0x6b, 0x3e, +0xfe, 0x75, 0xe9, 0xc0, 0xe1, 0xb5, 0xde, 0xaf, 0xdc, 0xac, 0xdd, 0xad, +0xe2, 0xb4, 0xed, 0xc1, 0xff, 0xe5, 0x6d, 0x48, 0x62, 0x36, 0x5d, 0x2e, +0x5c, 0x2d, 0x5e, 0x2f, 0x61, 0x33, 0x6a, 0x3d, 0x7e, 0x67, 0xeb, 0xc5, +0xe3, 0xb8, 0xde, 0xb0, 0xdc, 0xad, 0xdd, 0xae, 0xe1, 0xb4, 0xec, 0xc0, +0xfd, 0xdd, 0x6f, 0x4c, 0x63, 0x39, 0x5d, 0x2f, 0x5d, 0x2e, 0x5e, 0x2f, +0x61, 0x34, 0x69, 0x3d, 0x7c, 0x5e, 0xec, 0xc9, 0xe4, 0xba, 0xdf, 0xb3, +0xdd, 0xaf, 0xdd, 0xaf, 0xe1, 0xb5, 0xeb, 0xbf, 0xfa, 0xd9, 0x71, 0x50, +0x65, 0x3b, 0x5e, 0x32, 0x5d, 0x2f, 0x5e, 0x31, 0x61, 0x35, 0x68, 0x3d, +0x79, 0x59, 0xee, 0xcd, 0xe6, 0xbd, 0xe0, 0xb5, 0xdd, 0xb0, 0xdd, 0xb0, +0xe1, 0xb6, 0xeb, 0xbf, 0xf8, 0xd6, 0x74, 0x56, 0x66, 0x3d, 0x5f, 0x34, +0x5e, 0x31, 0x5e, 0x33, 0x61, 0x36, 0x67, 0x3d, 0x77, 0x55, 0xef, 0xd1, +0xe7, 0xbf, 0xe1, 0xb8, 0xde, 0xb2, 0xdd, 0xb2, 0xe1, 0xb7, 0xea, 0xbf, +0xf6, 0xd3, 0x77, 0x5c, 0x68, 0x40, 0x5f, 0x37, 0x5e, 0x33, 0x5f, 0x34, +0x61, 0x37, 0x67, 0x3e, 0x74, 0x52, 0xf3, 0xd7, 0xe8, 0xc1, 0xe2, 0xba, +0xdf, 0xb5, 0xde, 0xb3, 0xe0, 0xb8, 0xe9, 0xbf, 0xf5, 0xd2, 0x79, 0x62, +0x6a, 0x44, 0x61, 0x39, 0x5e, 0x35, 0x5f, 0x36, 0x62, 0x39, 0x67, 0x3e, +0x71, 0x4f, 0xf6, 0xde, 0xe9, 0xc5, 0xe4, 0xbc, 0xdf, 0xb7, 0xde, 0xb5, +0xe0, 0xb9, 0xe9, 0xc0, 0xf4, 0xd1, 0x7c, 0x6c, 0x6c, 0x49, 0x63, 0x3c, +0x5f, 0x37, 0x5f, 0x38, 0x62, 0x3a, 0x67, 0x3f, 0x6f, 0x4d, 0xf9, 0xe6, +0xeb, 0xc8, 0xe5, 0xbe, 0xe1, 0xba, 0xdf, 0xb7, 0xe0, 0xba, 0xe8, 0xc0, +0xf2, 0xd0, 0x7e, 0x7a, 0x6e, 0x4c, 0x64, 0x3e, 0x5f, 0x39, 0x60, 0x39, +0x63, 0x3b, 0x66, 0x3f, 0x6e, 0x4d, 0xfb, 0xef, 0xec, 0xcb, 0xe7, 0xc0, +0xe2, 0xbc, 0xdf, 0xb9, 0xe1, 0xbb, 0xe8, 0xc1, 0xf1, 0xcf, 0xff, 0xf6, +0x6f, 0x4f, 0x66, 0x40, 0x61, 0x3b, 0x61, 0x3b, 0x64, 0x3c, 0x66, 0x40, +0x6d, 0x4c, 0xfe, 0xff, 0xee, 0xce, 0xe8, 0xc4, 0xe4, 0xbd, 0xe0, 0xbb, +0xe1, 0xbc, 0xe8, 0xc2, 0xef, 0xce, 0xfd, 0xec, 0x72, 0x55, 0x67, 0x43, +0x62, 0x3d, 0x62, 0x3c, 0x64, 0x3e, 0x66, 0x41, 0x6d, 0x4c, 0x7f, 0x71, +0xef, 0xd3, 0xea, 0xc7, 0xe5, 0xbf, 0xe1, 0xbc, 0xe2, 0xbd, 0xe8, 0xc3, +0xef, 0xce, 0xfa, 0xe6, 0x75, 0x5a, 0x69, 0x47, 0x64, 0x3f, 0x64, 0x3e, +0x65, 0x3f, 0x67, 0x42, 0x6d, 0x4c, 0x7d, 0x6a, 0xf2, 0xd7, 0xeb, 0xca, +0xe7, 0xc2, 0xe3, 0xbe, 0xe3, 0xbe, 0xe8, 0xc5, 0xee, 0xce, 0xf9, 0xe2, +0x77, 0x5e, 0x6a, 0x4a, 0x65, 0x42, 0x65, 0x40, 0x65, 0x40, 0x67, 0x44, +0x6c, 0x4c, 0x7b, 0x66, 0xf5, 0xdc, 0xed, 0xcd, 0xe8, 0xc5, 0xe4, 0xc0, +0xe4, 0xc0, 0xe9, 0xc6, 0xee, 0xcf, 0xf7, 0xdf, 0x7a, 0x64, 0x6c, 0x4d, +0x67, 0x45, 0x66, 0x42, 0x66, 0x43, 0x67, 0x46, 0x6c, 0x4d, 0x79, 0x63, +0xf7, 0xe0, 0xee, 0xcf, 0xea, 0xc8, 0xe5, 0xc3, 0xe5, 0xc2, 0xe9, 0xc8, +0xee, 0xcf, 0xf6, 0xde, 0x7c, 0x6b, 0x6e, 0x50, 0x69, 0x48, 0x67, 0x45, +0x67, 0x45, 0x68, 0x47, 0x6c, 0x4e, 0x78, 0x60, 0xf9, 0xe7, 0xf0, 0xd4, +0xeb, 0xcb, 0xe7, 0xc6, 0xe6, 0xc5, 0xea, 0xc9, 0xee, 0xd0, 0xf5, 0xdd, +0x7e, 0x73, 0x6f, 0x55, 0x6a, 0x4b, 0x69, 0x48, 0x69, 0x48, 0x69, 0x49, +0x6c, 0x4e, 0x77, 0x5f, 0xfc, 0xed, 0xf3, 0xd8, 0xed, 0xce, 0xe8, 0xc9, +0xe7, 0xc8, 0xea, 0xcb, 0xee, 0xd1, 0xf5, 0xdd, 0xff, 0x7c, 0x72, 0x59, +0x6c, 0x4e, 0x6a, 0x4b, 0x6a, 0x4a, 0x6a, 0x4b, 0x6d, 0x4f, 0x76, 0x5f, +0xfd, 0xf3, 0xf5, 0xdc, 0xee, 0xd1, 0xea, 0xcc, 0xe9, 0xca, 0xeb, 0xcd, +0xee, 0xd3, 0xf4, 0xdd, 0xfe, 0xfc, 0x74, 0x5d, 0x6d, 0x51, 0x6c, 0x4d, +0x6b, 0x4d, 0x6b, 0x4d, 0x6d, 0x52, 0x76, 0x5f, 0xff, 0xfb, 0xf7, 0xdf, +0xef, 0xd5, 0xeb, 0xce, 0xea, 0xcc, 0xec, 0xcf, 0xef, 0xd5, 0xf4, 0xde, +0xfd, 0xf7, 0x77, 0x60, 0x6f, 0x55, 0x6d, 0x50, 0x6c, 0x4f, 0x6c, 0x4f, +0x6e, 0x54, 0x76, 0x5f, 0x7f, 0x7d, 0xfa, 0xe5, 0xf2, 0xda, 0xed, 0xd1, +0xeb, 0xcf, 0xed, 0xd1, 0xef, 0xd7, 0xf4, 0xde, 0xfc, 0xf2, 0x79, 0x66, +0x71, 0x59, 0x6e, 0x55, 0x6d, 0x53, 0x6d, 0x52, 0x6e, 0x57, 0x76, 0x60, +0x7e, 0x79, 0xfb, 0xea, 0xf5, 0xdd, 0xee, 0xd6, 0xed, 0xd3, 0xee, 0xd5, +0xf1, 0xda, 0xf4, 0xe0, 0xfb, 0xef, 0x7b, 0x6b, 0x73, 0x5d, 0x70, 0x59, +0x6f, 0x57, 0x6e, 0x56, 0x6f, 0x5a, 0x76, 0x62, 0x7d, 0x76, 0xfd, 0xee, +0xf7, 0xe1, 0xf1, 0xda, 0xee, 0xd7, 0xef, 0xd9, 0xf2, 0xdd, 0xf5, 0xe3, +0xfb, 0xef, 0x7c, 0x6f, 0x76, 0x61, 0x73, 0x5c, 0x71, 0x5b, 0x6f, 0x5a, +0x71, 0x5c, 0x77, 0x65, 0x7d, 0x75, 0xfd, 0xf3, 0xf9, 0xe7, 0xf4, 0xde, +0xf1, 0xdb, 0xf2, 0xdc, 0xf4, 0xdf, 0xf7, 0xe6, 0xfb, 0xef, 0x7e, 0x76, +0x78, 0x67, 0x75, 0x60, 0x74, 0x5e, 0x73, 0x5e, 0x73, 0x5f, 0x77, 0x67, +0x7d, 0x75, 0xfe, 0xf8, 0xfb, 0xeb, 0xf7, 0xe4, 0xf4, 0xdf, 0xf4, 0xdf, +0xf6, 0xe4, 0xf8, 0xe9, 0xfb, 0xf1, 0x7f, 0x7b, 0x7a, 0x6c, 0x78, 0x66, +0x77, 0x64, 0x76, 0x63, 0x76, 0x65, 0x79, 0x6a, 0x7d, 0x76, 0xff, 0xfb, +0xfc, 0xef, 0xf9, 0xea, 0xf7, 0xe6, 0xf7, 0xe6, 0xf8, 0xe9, 0xfa, 0xed, +0xfc, 0xf4, 0xff, 0x7e, 0x7c, 0x70, 0x7a, 0x6c, 0x79, 0x6a, 0x78, 0x69, +0x78, 0x6a, 0x7a, 0x6e, 0x7d, 0x78, 0xff, 0xfe, 0xfe, 0xf6, 0xfb, 0xef, +0xfa, 0xec, 0xf9, 0xec, 0xfb, 0xee, 0xfc, 0xf2, 0xfd, 0xf8, 0xff, 0x7f, +0x7e, 0x77, 0x7c, 0x72, 0x7c, 0x70, 0x7b, 0x6f, 0x7b, 0x70, 0x7c, 0x75, +0x7e, 0x7b, 0x7f, 0xff, 0xff, 0xfb, 0xfd, 0xf7, 0xfd, 0xf5, 0xfc, 0xf5, +0xfd, 0xf7, 0xfe, 0xf9, 0xfe, 0xfc, 0xff, 0xff, 0x7f, 0x7d, 0x7e, 0x7b, +0x7e, 0x7a, 0x7e, 0x7a, 0x7e, 0x7b, 0x7f, 0x7c, 0x7f, 0x7e, 0x7f, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; diff --git a/printer.c b/printer.c new file mode 100644 index 0000000..b307ad3 --- /dev/null +++ b/printer.c @@ -0,0 +1,310 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/************************DESCRIPTION*********************************** + Printer routine. Work like independent process. Albert +**********************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <arpa/inet.h> +#include "alh.h" +#ifdef HAVE_SYSV_IPC +#include <sys/msg.h> +#endif +#include <errno.h> +#include <alarm.h> +#include "printer.h" +#define DEBUG 0 + +char *colorStart[ALARM_NSEV]; +int colorStartLen[ALARM_NSEV]; +char *colorEnd; +int colorEndLen; +char msg[250]; +char buff[250]; + +int printerInit(char *,int); +int put2printer(char *,int,char *,int); +int compressMsg(char * msg, char *compress_buff); + +int main(int argc,char *argv[]) +{ +#ifdef HAVE_SYSV_IPC +int sev; /* define color for printer */ +struct msqid_ds infoBuf; +int printerMsgQId; +int printerMsgQKey; +int port; +int bytes=250; +int socket; + + /* OS specific initialization */ +#ifdef HP_UX + _main(); +#endif + if (argc != 5) { + fprintf(stderr,"usage:%s TCPName TCPport Key ColorModel\nColor model={bw,bw_bold,oki_bold,hp_color}\n",argv[0]); + exit(1); + } + if ( !(printerMsgQKey=atoi(argv[3])) || !(port=atoi(argv[2])) ) { + fprintf(stderr,"usage:%s TCPName TCPport Key ColorModel\nColor model={bw,bw_bold,oki_bold,hp_color}\n",argv[0]); + exit(1); + } + + if (strcmp(argv[4],"hp_color") == 0) { + colorStart[NO_ALARM]=&colorStartNoHpColor[0]; + colorStartLen[NO_ALARM]=colorStartNoHpColorLen; + colorStart[MINOR_ALARM]=&colorStartMinorHpColor[0]; + colorStartLen[MINOR_ALARM]=colorStartMinorHpColorLen; + colorStart[MAJOR_ALARM]=&colorStartMajorHpColor[0]; + colorStartLen[MAJOR_ALARM]=colorStartMajorHpColorLen; + colorStart[INVALID_ALARM]=&colorStartMinorHpColor[0]; + colorStartLen[INVALID_ALARM]=colorStartInvalidHpColorLen; + colorEnd=&colorEndHpColor[0]; + colorEndLen=colorEndHpColorLen; + } + + else if (strcmp(argv[4],"bw_bold") == 0) { + colorStart[NO_ALARM]=&colorStartNoMonoBold[0]; + colorStartLen[NO_ALARM]=colorStartNoMonoBoldLen; + colorStart[MINOR_ALARM]=&colorStartMinorMonoBold[0]; + colorStartLen[MINOR_ALARM]=colorStartMinorMonoBoldLen; + colorStart[MAJOR_ALARM]=&colorStartMajorMonoBold[0]; + colorStartLen[MAJOR_ALARM]=colorStartMajorMonoBoldLen; + colorStart[INVALID_ALARM]=&colorStartMinorMonoBold[0]; + colorStartLen[INVALID_ALARM]=colorStartInvalidMonoBoldLen; + colorEnd=&colorEndMonoBold[0]; + colorEndLen=colorEndMonoBoldLen; + } + + else if (strcmp(argv[4],"oki_bold") == 0) { + colorStart[NO_ALARM]=&colorStartNoOkiBold[0]; + colorStartLen[NO_ALARM]=colorStartNoOkiBoldLen; + colorStart[MINOR_ALARM]=&colorStartMinorOkiBold[0]; + colorStartLen[MINOR_ALARM]=colorStartMinorOkiBoldLen; + colorStart[MAJOR_ALARM]=&colorStartMajorOkiBold[0]; + colorStartLen[MAJOR_ALARM]=colorStartMajorOkiBoldLen; + colorStart[INVALID_ALARM]=&colorStartMinorOkiBold[0]; + colorStartLen[INVALID_ALARM]=colorStartInvalidOkiBoldLen; + colorEnd=&colorEndOkiBold[0]; + colorEndLen=colorEndOkiBoldLen; + } + + else { + colorStart[NO_ALARM]=&colorStartNoMono[0]; + colorStartLen[NO_ALARM]=colorStartNoMonoLen; + colorStart[MINOR_ALARM]=&colorStartMinorMono[0]; + colorStartLen[MINOR_ALARM]=colorStartMinorMonoLen; + colorStart[MAJOR_ALARM]=&colorStartMajorMono[0]; + colorStartLen[MAJOR_ALARM]=colorStartMajorMonoLen; + colorStart[INVALID_ALARM]=&colorStartMinorMono[0]; + colorStartLen[INVALID_ALARM]=colorStartInvalidMonoLen; + colorEnd=&colorEndMono[0]; + colorEndLen=colorEndMonoLen; + } + + printerMsgQId = msgget (printerMsgQKey, 0600|IPC_CREAT); + if(printerMsgQId == -1) {perror("msgQ_create"); exit(1);} + else + { + fprintf(stderr,"msgQ with key=%d is OK\n",printerMsgQKey); + if (msgctl(printerMsgQId,IPC_STAT,&infoBuf) != 1) + { + fprintf(stderr,"owner = %d.%d, perms = %04o, max bytes = %ld\n", + infoBuf.msg_perm.uid,infoBuf.msg_perm.gid, + infoBuf.msg_perm.mode,infoBuf.msg_qbytes); + fprintf(stderr,"%ld msgs = %ld bytes on queue\n", + infoBuf.msg_qnum, infoBuf.msg_cbytes); + } + else {perror("msgctl()"); exit(1);} + } + + fprintf(stderr,"Please wait ...\n"); + + if( (socket=printerInit(argv[1],port)) <= 0 ) { + perror("can't connect to TCPprinter"); + exit(1); + } + else fprintf(stderr,"printerInit for %s port=%d is OK\n",argv[1],port); + close(socket); + sleep(2); + + while(1) + { + if( msgrcv(printerMsgQId,msg,bytes,0,0) >= 0) /* got a new message */ + { + if ( (sev=compressMsg(msg+2,buff)) < 0 ) /* msg's big for 80char printer:cut it*/ + { perror("bad format"); continue;} + put2printer(argv[1],port,buff,strlen(buff)); + } + else usleep(1000); /* # in microsec */ + } + +} + +int printerInit(char *hostname,int port) +{ +int printerSocket; +struct sockaddr_in s_name; +struct hostent *h_ptr; +int true=1; + +if ((printerSocket=socket(AF_INET, SOCK_STREAM, 0)) == -1){ + perror( "socket"); + return(-1); +} + +if ((h_ptr = gethostbyname(hostname)) == NULL ) + { + perror("gethostbyname"); + exit(1); + } + +memset(&s_name, 0, sizeof(s_name)); +s_name.sin_family = AF_INET; +s_name.sin_port = htons(port); +memcpy(&s_name.sin_addr, h_ptr->h_addr, sizeof (s_name.sin_addr)); + +true=1; +if(setsockopt(printerSocket,SOL_SOCKET,SO_KEEPALIVE,(char *)&true,sizeof(true))) { + perror("Keepalive option set failed"); + return(-1); + } +true=1; + +if(setsockopt(printerSocket,IPPROTO_TCP,TCP_NODELAY,(char *)&true,sizeof(true))){ + perror("nodelay option set failed"); + return(-1); + } +true=128; +if(setsockopt(printerSocket,SOL_SOCKET,SO_SNDBUF,(char *)&true,sizeof(true))){ + perror("sendbuf option set failed"); + return(-1); + } + +if (connect(printerSocket, (struct sockaddr *) &s_name, sizeof (s_name)) ) { + perror("connect"); + close(printerSocket); + return(-1); +} + +return(printerSocket); +} + + +int put2printer(char *hostname,int port,char *string,int len) +{ +int printerSock; +int ret; + +while(1) + { + if( (printerSock=printerInit(hostname,port)) <= 0) { + sleep(1); + continue; + } + ret=send(printerSock,string,len,0); + if (ret != strlen(string)) { + fprintf(stderr,"Printer:Send_byte=%d need%d\n",ret,len); + } + close(printerSock); + usleep(1000); + return(0); + + } +} + +int compressMsg(char * msg, char *compress_buff) +{ +int sev,type; +char *blank; + /* We assume that mess has next format: + "typeOfRecord+1 time_stamp buff" + in regular case buff =(name al al_type h_al h_al_type value) + then we calculate sevirity: if typeOfRecord > 0 sev=MAJOR=2 -- service error; + if typeOfRecord=0 we calculate 3-rd word in buff + if word = NO_ALARM sev=0 + MINOR sev=1; + MAJOR sev=2; + INVALID sev =3; + all other sev=2; + + in regular case (typeOfRecord = 0) we cut al al_type h_al h_al_type till 5 char + in begin of compress_buff we add ColorStart-symbols and finish it ColorEnd-symbols, + so printer will print it in color!!! + */ + +if ( ( type = atoi(msg) ) == 0 ) { + fprintf(stderr,"%s: first element must be number\n",msg); + return(-1); +} + +if (type > 1) { + sprintf(compress_buff,"%s%s%s",colorStart[MAJOR_ALARM],msg+2,colorEnd); + if(DEBUG) fprintf(stderr,"buff=%s;",compress_buff); + return(MAJOR_ALARM); +} + +/* EXAMPLE:0 01-Apr-1999 12:39:49 AHTST:out2_ao NO_ALARM NO_ALARM HIHI MAJOR 0.00 + + 20 +1 +28 +1 +12 +1 +16 +1+12+1+16 +1 + | | | | | | | | + 0 2 23 52 65 82 95 112 + */ + +if (strncmp(msg+52,"NO_ALARM",7) == 0) sev=0; +else if (strncmp(msg+52,"MINOR" ,5) == 0) sev=1; +else if (strncmp(msg+52,"INVALID", 6) == 0) sev=3; +else sev=2; + +strcpy (compress_buff,colorStart[sev]); /* color symb */ +strncat(compress_buff,msg+2,20); /* TS */ + +if ( (blank = strchr( (const char *) msg+23, ' ')) == NULL) { + fprintf(stderr,"%s: bad 1 blank in msg \n",msg); + return(-1); +} + +strncat(compress_buff,msg+22,blank - msg-22 ); /* blank + name */ +strncat(compress_buff,msg+51,6); /* blank + first 5 symbols of alarm */ +strncat(compress_buff,msg+64,6); /* blank + first 5 symbols of sev */ +strcat (compress_buff,msg+111); /* blank +value */ +strcat (compress_buff,colorEnd); /* color symb */ +strcat (compress_buff,"\n"); /* \n-it's important for printer */ + +if(DEBUG) fprintf(stderr,"uncompress buff=%s;\n compress buff=%s;\n",msg,compress_buff); + +return(sev); +} + + + + + + + + + + +#else /* HAVE_SYSV_IPC */ + return 1; +} +#endif /* HAVE_SYSV_IPC */ diff --git a/printer.h b/printer.h new file mode 100644 index 0000000..1a5dbb3 --- /dev/null +++ b/printer.h @@ -0,0 +1,117 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* printer.h */ + +/************************DESCRIPTION*********************************** + In this file we describe esq. sequense for coloring alarm + for different type of printer. + See http://hpcc920.external.hp.com/cposupport/eschome.html + for the other HP printer +**********************************************************************/ + +#ifndef INCprinterh +#define INCprinterh 1 + +/* ------------- Mono Bold printer ---------------------------------- */ + +char colorStartNoMonoBold[] ={ + 0}; +int colorStartNoMonoBoldLen=0; + +char colorStartMinorMonoBold[] ={ + 0}; +int colorStartMinorMonoBoldLen=0; + +char colorStartMajorMonoBold[]={ + 27,'[','1','m',0}; /*BOLD letters*/ +int colorStartMajorMonoBoldLen=5; + +char colorStartInvalidMonoBold[]={ + 27,'[','1','m',0};/*BOLD letters*/ +int colorStartInvalidMonoBoldLen=5; + +char colorEndMonoBold[]={ + 27,'[','0','m',0}; +int colorEndMonoBoldLen=5; + +/* ------------- Mono OKI printer ---------------------------------- */ + +char colorStartNoOkiBold[] ={ + 0}; +int colorStartNoOkiBoldLen=0; + +char colorStartMinorOkiBold[] ={ + 0}; +int colorStartMinorOkiBoldLen=0; + +char colorStartMajorOkiBold[]={ + 27,72,0}; /*BOLD letters*/ +int colorStartMajorOkiBoldLen=3; + +char colorStartInvalidOkiBold[]={ + 27,72,0};/*BOLD letters*/ +int colorStartInvalidOkiBoldLen=3; + +char colorEndOkiBold[]={ + 27,73,0}; +int colorEndOkiBoldLen=3; + +/* ------------- HP DeskJet 1200C ---------------------------------- */ + +char colorStartNoHpColor[] ={ + 0}; +int colorStartNoHpColorLen=0; + +char colorStartMinorHpColor[] ={ + 27,'&','v','3','S',0}; +int colorStartMinorHpColorLen=6; /*YELLOW letters*/ + +char colorStartMajorHpColor[]={ + 27,'&','v','1','S',0}; +int colorStartMajorHpColorLen=6; /*RED letters*/ + +char colorStartInvalidHpColor[]={ + 27,'&','v','5','S',0}; +int colorStartInvalidHpColorLen=6; /* Magenta letters*/ + +char colorEndHpColor[]={ + 27,'E',0}; +int colorEndHpColorLen=3; + +/* ------------- Mono printer ---------------------------------- */ + +char colorStartNoMono[] ={ + 0}; +int colorStartNoMonoLen=0; + +char colorStartMinorMono[] ={ + 0}; +int colorStartMinorMonoLen=0; + +char colorStartMajorMono[]={ + 0}; +int colorStartMajorMonoLen=0; + +char colorStartInvalidMono[]={ + 0}; +int colorStartInvalidMonoLen=0; + +char colorEndMono[]={ + 0}; +int colorEndMonoLen=1; + + +#endif /* INCprinterh */ + diff --git a/process.c b/process.c new file mode 100644 index 0000000..c90252d --- /dev/null +++ b/process.c @@ -0,0 +1,261 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* process.c */ + +/************************DESCRIPTION*********************************** + This file contains routines for spawning a related process +**********************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#ifdef WIN32 +#include <process.h> /* For spawn */ +#endif +#include <Xm/Xm.h> +#include <Xm/RowColumn.h> +#include <Xm/PushB.h> + +#include "alLib.h" +#include "ax.h" + +#define masterCommand "MASTER_ONLY" +extern int DEBUG; + +extern int _lock_flag; +extern int masterFlag; +extern int notsave; + +static char *g_popupCmdString; +static Widget g_pum = NULL; +#ifdef WIN32 +#define strtok_r strtok_s +#endif + +/****************************************************** + spawn a new related prcess if command is not null +******************************************************/ +void processSpawn_callback(Widget w,char *command,void * call_data) +{ + char buff[MAX_STRING_LENGTH +2]; + int l; + int status; +#ifdef WIN32 + static int first=1; + static char *ComSpec; +#endif + +if(notsave) { fprintf(stderr,"NOT SAVE mode - no related process started"); return;} + + if (command) { + /* Strip any LF from the end */ + l = strlen(command); + if (*(command+l-1) == '\n') *(command+l-1) = ' '; + +/* If more then 1 alh process work with the same config files +of cource, usually all this process can span all callback, +BUT in some special case (in our situation it's mail to +mobil-phone) it's expensive (in money :) or processor-time) +or not so important. In this case ONLY master alh_process +span this task. For distinguish with common case we add +additional last parameters in command MASTER_ONLY: +WAS: $SEVRCOMMAND UP_ERROR mailx mobil@server.com "ALARM HAPPEN" +NOW: $SEVRCOMMAND UP_ERROR MASTER_ONLY mailx mobil@server.com "ALARM HAPPEN" + +Coding: +------ + +If don't locking system -- cut MASTER_ONLY from string and spawn it +Else if you're master-alh-process -- the same + else do nothing +*/ + /* ________MASTER_ONLY code ________________________ */ + if(strncmp(command,masterCommand,strlen(masterCommand))==0) + { + command += strlen(masterCommand); + if (_lock_flag && !masterFlag) return; + } + /* _______End MASTER_ONLY code ______________________ */ + +#ifdef WIN32 + sprintf(buff,"%s",command); + /* Get ComSpec for the command shell (should be defined) */ + if (first) { + first=0; + ComSpec = getenv("ComSpec"); + } + if (!ComSpec) { + errMsg("processSpawn_callback: Cannot find command processor\n"); + return; + } + status = _spawnl(_P_DETACH, ComSpec, ComSpec, "/C", buff, NULL); +#else + sprintf(buff,"%s &",command); + status=system(buff); +#endif + if(status == -1) { + /* System call failed */ + char *errstring=strerror(errno); + + errMsg("processSpawn_callback: Cannot process command:\n" + "%s\n %s", + buff,errstring); + } else if (status > 0) { + /* Assume program returned an error */ + errMsg("processSpawn_callback: Command returned %d:\n" + "%s\n", + status,buff); + } + } +} + +/*************************************************** + menu callback +****************************************************/ +static void relprocmenu_cb ( + Widget w, + XtPointer index, + void * call_data +) { + +char buf[1023+1], *tk, *ctx; +int i; +int indexi = (long) index; + + strncpy( buf, g_popupCmdString, 1023 ); + buf[1023] = 0; + + i = 0; + ctx = NULL; + tk = strtok_r( buf, "!\n", &ctx ); + while ( tk ) { + tk = strtok_r( NULL, "!\n", &ctx ); + if ( tk ) { + if ( i == indexi ) { + processSpawn_callback( w, tk, call_data ); + return; + } + i++; + } + tk = strtok_r( NULL, "!\n", &ctx ); + }; + +} + +/*************************************************** + relatedProcess_callback +****************************************************/ +void relatedProcess_callback(void *widget,GCLINK *link,void *cbs) +{ + void *area; + char buf[1023+1], *tk, *ctx; + int i, n; + Widget pdm, pb; + Arg args[10]; + XmString str; + Window root, child; + int rootX, rootY, winX, winY; + unsigned int mask; + XButtonEvent be; + + XtVaGetValues(widget, XmNuserData, &area, NULL); + + if (link && alProcessExists(link)){ + + strncpy( buf, link->pgcData->command, 1023 ); + buf[1023] = 0; + + i = 0; + ctx = NULL; + tk = strtok_r( buf, "!\n", &ctx ); + while ( tk ) { + if ( tk ) { + i++; + } + tk = strtok_r( NULL, "!\n", &ctx ); + }; + + if ( i > 1 ) { + + if ( i % 2 ) { /* if i > one then i must be even */ + fprintf( stderr, "Command syntax error\n" ); + return; + } + + g_popupCmdString = link->pgcData->command; + + if ( g_pum ) { + XtDestroyWidget( g_pum ); + g_pum = NULL; + } + + n = 0; + XtSetArg( args[n], XmNpopupEnabled, (XtArgVal) False ); n++; + g_pum = XmCreatePopupMenu( topLevelShell, "relprocmenu", args, n ); + + pdm = XmCreatePulldownMenu( g_pum, "relprocpd", NULL, 0 ); + + strncpy( buf, link->pgcData->command, 1023 ); + buf[1023] = 0; + + i = 0; + ctx = NULL; + tk = strtok_r( buf, "!\n", &ctx ); + + while ( tk ) { + + if ( tk ) { + + long ilong = i; + str = XmStringCreateLocalized( tk ); + pb = XtVaCreateManagedWidget( "pb", xmPushButtonWidgetClass, + g_pum, XmNlabelString, str, NULL ); + XmStringFree( str ); + XtAddCallback( pb, XmNactivateCallback, relprocmenu_cb, + (XtPointer)ilong ); + + i++; + + } + + tk = strtok_r( NULL, "!\n", &ctx ); + tk = strtok_r( NULL, "!\n", &ctx ); + + }; + + XQueryPointer( display, XtWindow(XtParent(widget)), &root, &child, + &rootX, &rootY, &winX, &winY, &mask ); + + be.x_root = rootX; + be.y_root = rootY; + + XmMenuPosition( g_pum, &be ); + XtManageChild( g_pum ); + + } + else { + + strncpy( buf, link->pgcData->command, 1023 ); + buf[1023] = 0; + + ctx = NULL; + tk = strtok_r( buf, "!\n", &ctx ); + processSpawn_callback( widget, tk, cbs ); + + } + + } + +} diff --git a/productDescriptionShell.c b/productDescriptionShell.c new file mode 100644 index 0000000..aec7155 --- /dev/null +++ b/productDescriptionShell.c @@ -0,0 +1,532 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* productDescriptionShell.c */ + +/************************DESCRIPTION*********************************** + routine to create product description shell for all Motif-based EPICS tools + input parameters are the product name, and product description +**********************************************************************/ + +#define VERSION 1.1.0 + +#define DEBUG_POSITION 0 + +#include <stdio.h> + +#include <X11/StringDefs.h> +#include <X11/Intrinsic.h> +#include <X11/Xatom.h> +#include <Xm/Xm.h> +#include <Xm/Protocols.h> + +#include <Xm/Label.h> +#include <Xm/Form.h> +#include <Xm/Separator.h> +#include <Xm/PushB.h> +#include <Xm/MwmUtil.h> + +#ifdef WIN32 +/* Hummingbird extra functions including lprintf + * Needs to be included after Intrinsic.h for Exceed 5 */ +#include <X11/XlibXtra.h> +#define printf lprintf +#endif + +static Widget okButton; + +/* forward declarations */ +static void closeProductDescriptionCallback(Widget w, +XtPointer client_data, XtPointer call_data); +static void popdownProductDescriptionShell(XtPointer xtPointer); + +/********************************************************* + closeProductDescriptionCallback +*********************************************************/ +static void closeProductDescriptionCallback(Widget w, +XtPointer client_data, XtPointer call_data) +{ + Widget shell = (Widget)client_data; + XtPopdown(shell); +} + +/********************************************************* + popdownProductDescriptionShell +*********************************************************/ +static void popdownProductDescriptionShell(XtPointer xtPointer) +{ + Arg args[3]; + Widget widget; + Atom WM_DELETE_WINDOW; + + widget = (Widget) xtPointer; + XtPopdown(widget); + + XtSetArg(args[0],XmNmwmDecorations,MWM_DECOR_ALL); + XtSetArg(args[1],XmNdeleteResponse,XmDO_NOTHING); + XtSetValues(widget,args,2); + + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(widget), + "WM_DELETE_WINDOW",False); + XmAddWMProtocolCallback(widget,WM_DELETE_WINDOW, + (XtCallbackProc)closeProductDescriptionCallback,(XtPointer)widget); + + /* Next time up the OK button will show */ + XtManageChild(okButton); +} + + +/********************************************************* + * createAndPopupProductDescriptionShell + * + * function to create, set and popup an EPICS product description shell + * widget hierarchy: + * + * productDescriptionShell + * form + * nameLabel + * separator + * descriptionLabel + * versionInfoLabel + * developedAtLabel + * okButton +*********************************************************/ +Widget createAndPopupProductDescriptionShell( +XtAppContext appContext, /* application context */ +Widget topLevelShell, /* application's topLevel shell */ +char *name, /* product/program name */ +XmFontList nameFontList, /* and font list (or NULL) */ +Pixmap namePixmap, /* name Pixmap (or NULL) */ +char *description, /* product description */ +XmFontList descriptionFontList,/* and font list (or NULL) */ +char *versionInfo, /* product version number */ +char *developedAt, /* at and by... */ +XmFontList otherFontList, /* and font list (or NULL) */ +int background, /* background color (or -1) */ +int foreground, /* foreground color (or -1) */ +int seconds) /* seconds to leave posted */ +{ + Display *display; + Widget productDescriptionShell, form; + Arg args[15]; + Widget children[6], nameLabel, descriptionLabel, versionInfoLabel, + separator, developedAtLabel; + XmString nameXmString = (XmString)NULL, descriptionXmString = (XmString)NULL, + versionInfoXmString = (XmString)NULL, + developedAtXmString = (XmString)NULL, okXmString = (XmString)NULL; + Dimension formHeight, nameHeight; + Dimension shellHeight, shellWidth; + Dimension screenHeight, screenWidth; + Position newY, newX; + int n, offset, screen; + + + /* Create the shell */ + n = 0; + if (background >= 0) { + XtSetArg(args[n],XmNbackground,(unsigned long)background); + n++; + } + if (foreground >= 0) { + XtSetArg(args[n],XmNforeground,(unsigned long)foreground); + n++; + } + XtSetArg(args[n],XmNmwmDecorations, MWM_DECOR_ALL| + MWM_DECOR_BORDER|MWM_DECOR_RESIZEH|MWM_DECOR_TITLE|MWM_DECOR_MENU| + MWM_DECOR_MINIMIZE|MWM_DECOR_MAXIMIZE); + n++; + XtSetArg(args[n],XmNtitle,"Version"); + n++; + productDescriptionShell = XtCreatePopupShell("productDescriptionShell", + topLevelShellWidgetClass,topLevelShell,args, n); + display=XtDisplay(productDescriptionShell); + screen=DefaultScreen(display); + + n = 0; + if (background >= 0) { + XtSetArg(args[n],XmNbackground,(unsigned long)background); + n++; + } + if (foreground >= 0) { + XtSetArg(args[n],XmNforeground,(unsigned long)foreground); + n++; + } + XtSetArg(args[n],XmNnoResize,True); + n++; + XtSetArg(args[n],XmNshadowThickness,2); + n++; + XtSetArg(args[n],XmNshadowType,XmSHADOW_OUT); + n++; + XtSetArg(args[n],XmNautoUnmanage,False); + n++; + form = XmCreateForm(productDescriptionShell,"form",args,n); + + /* Generate XmStrings */ + if (name != NULL) nameXmString = XmStringCreateLtoR(name, + XmFONTLIST_DEFAULT_TAG); + if (description != NULL) descriptionXmString = + XmStringCreateLtoR(description,XmFONTLIST_DEFAULT_TAG); + if (versionInfo != NULL) versionInfoXmString = + XmStringCreateLtoR(versionInfo,XmFONTLIST_DEFAULT_TAG); + if (developedAt != NULL) developedAtXmString = + XmStringCreateLtoR(developedAt,XmFONTLIST_DEFAULT_TAG); + + /* Create the label children */ + /* Name */ + n = 0; + if (namePixmap == (Pixmap) NULL) { + XtSetArg(args[n],XmNlabelString,nameXmString); + n++; + if (nameFontList != NULL) { + XtSetArg(args[n],XmNfontList,nameFontList); + n++; + } + } else { + XtSetArg(args[n],XmNlabelType,XmPIXMAP); + n++; + XtSetArg(args[n],XmNlabelPixmap,namePixmap); + n++; + } + XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); + n++; + XtSetArg(args[n],XmNleftAttachment,XmATTACH_POSITION); + n++; + XtSetArg(args[n],XmNleftPosition,1); + n++; + XtSetArg(args[n],XmNresizable,False); + n++; + if (background >= 0) { + XtSetArg(args[n],XmNbackground,(unsigned long)background); + n++; + } + if (foreground >= 0) { + XtSetArg(args[n],XmNforeground,(unsigned long)foreground); + n++; + } + nameLabel = XmCreateLabel(form,"nameLabel",args,n); + + + /* Separator */ + n = 0; + XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); + n++; + XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); + n++; + XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); + n++; + XtSetArg(args[n],XmNleftWidget,nameLabel); + n++; + XtSetArg(args[n],XmNorientation,XmVERTICAL); + n++; + XtSetArg(args[n],XmNshadowThickness,2); + n++; + XtSetArg(args[n],XmNseparatorType,XmSHADOW_ETCHED_IN); + n++; + if (background >= 0) { + XtSetArg(args[n],XmNbackground,(unsigned long)background); + n++; + } + if (foreground >= 0) { + XtSetArg(args[n],XmNforeground,(unsigned long)foreground); + n++; + } + separator = XmCreateSeparator(form,"separator",args,n); + + /* Description */ + n = 0; + XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); + n++; + XtSetArg(args[n],XmNlabelString,descriptionXmString); + n++; + XtSetArg(args[n],XmNtopAttachment,XmATTACH_POSITION); + n++; + XtSetArg(args[n],XmNtopPosition,5); + n++; + XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); + n++; + XtSetArg(args[n],XmNleftWidget,separator); + n++; + XtSetArg(args[n],XmNrightAttachment,XmATTACH_POSITION); + n++; + XtSetArg(args[n],XmNrightPosition,90); + n++; + if (descriptionFontList != NULL) { + XtSetArg(args[n],XmNfontList,descriptionFontList); + n++; + } + if (background >= 0) { + XtSetArg(args[n],XmNbackground,(unsigned long)background); + n++; + } + if (foreground >= 0) { + XtSetArg(args[n],XmNforeground,(unsigned long)foreground); + n++; + } + descriptionLabel = XmCreateLabel(form,"descriptionLabel",args,n); + + /* Version info */ + n = 0; + XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); + n++; + XtSetArg(args[n],XmNlabelString,versionInfoXmString); + n++; + XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); + n++; + XtSetArg(args[n],XmNtopWidget,descriptionLabel); + n++; + XtSetArg(args[n],XmNleftAttachment,XmATTACH_OPPOSITE_WIDGET); + n++; + XtSetArg(args[n],XmNleftWidget,descriptionLabel); + n++; + XtSetArg(args[n],XmNrightAttachment,XmATTACH_POSITION); + n++; + XtSetArg(args[n],XmNrightPosition,90); + n++; + if (otherFontList != NULL) { + XtSetArg(args[n],XmNfontList,otherFontList); + n++; + } + if (background >= 0) { + XtSetArg(args[n],XmNbackground,(unsigned long)background); + n++; + } + if (foreground >= 0) { + XtSetArg(args[n],XmNforeground,(unsigned long)foreground); + n++; + } + versionInfoLabel = XmCreateLabel(form,"versionInfoLabel",args,n); + + /* Developed at/by... */ + n = 0; + XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); + n++; + XtSetArg(args[n],XmNlabelString,developedAtXmString); + n++; + XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); + n++; + XtSetArg(args[n],XmNtopWidget,versionInfoLabel); + n++; + XtSetArg(args[n],XmNleftAttachment,XmATTACH_OPPOSITE_WIDGET); + n++; + XtSetArg(args[n],XmNleftWidget,versionInfoLabel); + n++; + XtSetArg(args[n],XmNrightAttachment,XmATTACH_POSITION); + n++; + XtSetArg(args[n],XmNrightPosition,90); + n++; + XtSetArg(args[n],XmNbottomAttachment,XmATTACH_POSITION); + n++; + XtSetArg(args[n],XmNbottomPosition,90); + n++; + + if (otherFontList != NULL) { + XtSetArg(args[n],XmNfontList,otherFontList); + n++; + } + if (background >= 0) { + XtSetArg(args[n],XmNbackground,(unsigned long)background); + n++; + } + if (foreground >= 0) { + XtSetArg(args[n],XmNforeground,(unsigned long)foreground); + n++; + } + developedAtLabel = XmCreateLabel(form,"developedAtLabel",args,n); + + + /* OK button */ + okXmString = XmStringCreateLocalized("OK"); + n = 0; + XtSetArg(args[n],XmNlabelString,okXmString); + n++; + XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); + n++; + XtSetArg(args[n],XmNtopOffset,8); + n++; + XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); + n++; + XtSetArg(args[n],XmNrightOffset,8); + n++; + if (otherFontList != NULL) { + XtSetArg(args[n],XmNfontList,otherFontList); + n++; + } + if (background >= 0) { + XtSetArg(args[n],XmNbackground,(unsigned long)background); + n++; + } + if (foreground >= 0) { + XtSetArg(args[n],XmNforeground,(unsigned long)foreground); + n++; + } + okButton = XmCreatePushButton(form,"okButton",args,n); + XtAddCallback(okButton,XmNactivateCallback, + (XtCallbackProc)closeProductDescriptionCallback, + (XtPointer)productDescriptionShell); + n++; + XmStringFree(okXmString); + + children[0] = nameLabel; + children[1] = descriptionLabel; + children[2] = versionInfoLabel; + children[3] = developedAtLabel; + children[4] = separator; + XtManageChildren(children,5); + XtManageChild(form); + + XtPopup(productDescriptionShell,XtGrabNone); + + /* Center nameLabel vertically in form space */ + XtSetArg(args[0],XmNheight,&nameHeight); + XtGetValues(nameLabel,args,1); + XtSetArg(args[0],XmNheight,&formHeight); + XtGetValues(form,args,1); + offset = (formHeight - nameHeight); + offset = offset/2; + XtSetArg(args[0],XmNtopOffset,offset); + XtSetValues(nameLabel,args,1); + + /* Center the whole thing on the screen */ + screenHeight=DisplayHeight(display,screen); + screenWidth=DisplayWidth(display,screen); + + n=0; + XtSetArg(args[n],XmNheight,&shellHeight); + n++; + XtSetArg(args[n],XmNwidth,&shellWidth); + n++; + XtGetValues(productDescriptionShell,args,n); + + newY=(screenHeight-shellHeight)/2; + newX=(screenWidth-shellWidth)/2; + + n=0; + XtSetArg(args[n],XmNy,newY); + n++; + XtSetArg(args[n],XmNx,newX); + n++; + XtSetValues(productDescriptionShell,args,n); + +#ifdef WIN32 + /* Seems to be an Exceed bug that it doesn't get set the first time */ + n=0; + XtSetArg(args[n],XmNy,newY); + n++; + XtSetArg(args[n],XmNx,newX); + n++; + XtSetValues(productDescriptionShell,args,n); +#endif + +#if DEBUG_POSITION + { + Position newx, newy; + + printf("createAndPopupProductDescriptionShell:\n"); + printf(" sizeof(XtArgVal)=%d sizeof(Position)=%d sizeof(Dimension)=%d sizeof(100)=%d\n", + sizeof(XtArgVal),sizeof(Position),sizeof(Dimension),sizeof(100)); + printf(" shellHeight=%d shellWidth=%d\n",shellHeight,shellWidth); + printf(" screenHeight=%d screenWidth=%d\n",screenHeight,screenWidth); + printf(" newY=%hd newX=%hd\n",newY,newX); + printf(" newY=%hx newX=%hx\n",newY,newX); + printf(" newY=%x newX=%x\n",newY,newX); + + printf("(1) args[0].value=%4x args[1].value=%4x\n",args[0].value,args[1].value); + + n=0; + XtSetArg(args[n],XmNy,&newy); + n++; + XtSetArg(args[n],XmNx,&newx); + n++; + XtGetValues(productDescriptionShell,args,n); + + printf("(1) newy=%d newx=%d\n",newy,newx); + + n=0; + XtSetArg(args[n],XmNy,474); + n++; + XtSetArg(args[n],XmNx,440); + n++; + XtSetValues(productDescriptionShell,args,n); + + printf("(2) args[0].value=%4x args[1].value=%4x\n",args[0].value,args[1].value); + + n=0; + XtSetArg(args[n],XmNy,&newy); + n++; + XtSetArg(args[n],XmNx,&newx); + n++; + XtGetValues(productDescriptionShell,args,n); + + printf("(2) newy=%d newx=%d\n",newy,newx); + + n=0; + XtSetArg(args[n],XmNy,newY); + n++; + XtSetArg(args[n],XmNx,newX); + n++; + XtSetValues(productDescriptionShell,args,n); + + printf("(3) args[0].value=%4x args[1].value=%4x\n",args[0].value,args[1].value); + + n=0; + XtSetArg(args[n],XmNy,&newy); + n++; + XtSetArg(args[n],XmNx,&newx); + n++; + XtGetValues(productDescriptionShell,args,n); + + printf("(3) newy=%d newx=%d\n",newy,newx); + + } +#endif + + /* Free strings */ + if (nameXmString != (XmString)NULL) XmStringFree(nameXmString); + if (descriptionXmString != (XmString)NULL) XmStringFree(descriptionXmString); + if (versionInfoXmString != (XmString)NULL) XmStringFree(versionInfoXmString); + if (developedAtXmString != (XmString)NULL) XmStringFree(developedAtXmString); + + /* Register timeout procedure to make the dialog go away after N seconds */ + XtAppAddTimeOut(appContext,(unsigned long)(1000*seconds), + (XtTimerCallbackProc)popdownProductDescriptionShell, + (XtPointer)productDescriptionShell); + + return(productDescriptionShell); +} + + +#ifdef TEST_PRODUCT_DESCRIPTION_SHELL +/*************************************************************************/ + +main(int argc, char **argv) +{ + Widget topLevel, shell; + XtAppContext appContext; + + topLevel = XtAppInitialize(&appContext, "TEST", NULL, 0, &argc, argv, + fallbackResources, NULL, 0); + XmRegisterConverters(); + shell = createAndPopupProductDescriptionShell(appContext,topLevel, + "MEDM", NULL,(Pixmap)NULL, + "Motif-based Editor & Display Manager", NULL, + "Version "VERSION, + "developed at Argonne National Laboratory, by Mark Anderson", NULL, + -1, -1, 3); + + + XtRealizeWidget(topLevel); + XtAppMainLoop(appContext); + +} +#endif /* TEST */ diff --git a/property.c b/property.c new file mode 100644 index 0000000..a51ffc1 --- /dev/null +++ b/property.c @@ -0,0 +1,1908 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* property.c */ + +/************************DESCRIPTION*********************************** + routines for display of group and channel properties +**********************************************************************/ + +#include <stdlib.h> +#include <stdio.h> + +#include <Xm/Xm.h> +#include <Xm/AtomMgr.h> +#include <Xm/DialogS.h> +#include <Xm/Form.h> +#include <Xm/Frame.h> +#include <Xm/LabelG.h> +#include <Xm/PushB.h> +#include <Xm/ToggleB.h> +#include <Xm/PanedW.h> +#include <Xm/Protocols.h> +#include <Xm/RowColumn.h> +#include <Xm/ScrolledW.h> +#include <Xm/Text.h> +#include <Xm/TextF.h> +#include <Xm/ToggleBG.h> + +#include "alarm.h" +#include "axArea.h" +#include "alLib.h" +#include "ax.h" + +extern Pixel bg_pixel[ALH_ALARM_NSEV]; + +struct propWindow { + void *area; + Widget menuButton; + Widget propDialog; + Widget nameLabelW; + Widget nameTextW; + Widget alarmMaskStringLabelW; + Widget alarmMaskToggleButtonW[ALARM_NMASK]; + Widget resetMaskStringLabelW; + Widget maskFrameW; + Widget beepSeverityValueTextW; + Widget severityPVnameTextW; + Widget countFilterFrame; + Widget countFilterCountTextW; + Widget countFilterSecondsTextW; + Widget forcePVnameTextW; + Widget forcePVForceMaskStringLabelW; + Widget forceMaskToggleButtonW[ALARM_NMASK]; + Widget forcePVcurrentValueTextW; + Widget forcePVforceValueTextW; + Widget forcePVresetValueTextW; + Widget forcePVCalcExpressionTextW; + Widget forcePVCalcPVTextW[NO_OF_CALC_PVS]; + Widget aliasTextW; + Widget processTextW; + Widget statProcessTextW; + Widget sevrProcessTextW; + Widget guidanceTextW; + Widget guidanceUrlW; + +}; + +extern char * alhAlarmSeverityString[]; + +/* forward declarations */ +static void propApplyCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void propCancelCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void propDismissCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void propHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void propCreateDialog(ALINK*area); +static void propUpdateDialogWidgets(struct propWindow *propWindow); +static void propMaskChangeCallback( Widget widget,XtPointer calldata,XtPointer cbs); +static void propEditableDialogWidgets(ALINK *area); +static GCLINK *propCreateClone(GCLINK *link,int linkType); + +#if 0 +static void propDeleteClone(GCLINK *link,int linkType); +#endif + +/****************************************************** + propUpdateDialog +******************************************************/ +void propUpdateDialog(ALINK *area) +{ + struct propWindow *propWindow; + + propWindow = (struct propWindow *)area->propWindow; + + if (!propWindow) return; + + if (!propWindow->propDialog || !XtIsManaged(propWindow->propDialog)) return; + + propUpdateDialogWidgets(propWindow); + +} + +/****************************************************** + propShowDialog +******************************************************/ +void propShowDialog(ALINK *area,Widget menuButton) +{ + struct propWindow *propWindow; + + propWindow = (struct propWindow *)area->propWindow; + + /* dismiss Dialog */ + if (propWindow && propWindow->propDialog && + XtIsManaged(propWindow->propDialog)) { + propDismissCallback(NULL, (XtPointer)propWindow, NULL); + return; + } + + /* create propWindow and Dialog Widgets if necessary */ + if (!propWindow) propCreateDialog(area); + + /* update propWindow link info */ + propWindow = (struct propWindow *)area->propWindow; + propWindow->menuButton = menuButton; + + /* update Dialog Widgets */ + propUpdateDialogWidgets(propWindow); + + /* show Dialog */ + if (!propWindow->propDialog) return; + if (!XtIsManaged(propWindow->propDialog)) { + XtManageChild(propWindow->propDialog); + } + XMapWindow(XtDisplay(propWindow->propDialog), + XtWindow(XtParent(propWindow->propDialog))); + if (menuButton) XtVaSetValues(menuButton, XmNset, TRUE, NULL); + +} + +/****************************************************** + propUpdateDialogWidgets +******************************************************/ +static void propUpdateDialogWidgets(struct propWindow *propWindow) +{ + struct gcData *pgcData; + struct chanData *pcData = 0; + GCLINK *link; + int linkType; + XmString string; + char buff[MAX_STRING_LENGTH]; + char buff1[MAX_STRING_LENGTH]; + char *str; + SNODE *pt; + int i=0; + struct guideLink *guideLink; + MASK mask; + Pixel textBackground; + Pixel textBackgroundNS; + + if (programId != ALH) textBackground = bg_pixel[3]; + else textBackground = bg_pixel[0]; + textBackgroundNS = bg_pixel[0]; + + link =getSelectionLinkArea(propWindow->area); + + if (! propWindow || !propWindow->propDialog) return; + + if (!link) { + + XmTextFieldSetString(propWindow->nameTextW, ""); + string = XmStringCreateSimple("-----"); + XtVaSetValues(propWindow->alarmMaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + if (programId == ALH) { + string = XmStringCreateSimple("-"); + XtVaSetValues(propWindow->resetMaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + } + if (programId != ALH) { + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[0],FALSE,TRUE); + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[1],FALSE,TRUE); + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[2],FALSE,TRUE); + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[3],FALSE,TRUE); + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[4],FALSE,TRUE); + } + XmTextFieldSetString(propWindow->beepSeverityValueTextW,""); + XmTextFieldSetString(propWindow->severityPVnameTextW,""); + XmTextFieldSetString(propWindow->countFilterCountTextW,""); + XmTextFieldSetString(propWindow->countFilterSecondsTextW,""); + + + + /* ForcePV data */ + XmTextFieldSetString(propWindow->forcePVnameTextW,""); + string = XmStringCreateSimple("-----"); + XtVaSetValues(propWindow->forcePVForceMaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); +/* + if (programId == ALH) { + string = XmStringCreateSimple(""); + XtVaSetValues(propWindow->forcePVcurrentValueTextW, XmNlabelString, string, NULL); + XmStringFree(string); + } +*/ + XmTextFieldSetString(propWindow->forcePVforceValueTextW,""); + XmTextFieldSetString(propWindow->forcePVresetValueTextW,""); + XmTextFieldSetString(propWindow->forcePVCalcExpressionTextW,""); + for (i=0;i<NO_OF_CALC_PVS;i++){ + XmTextFieldSetString(propWindow->forcePVCalcPVTextW[i],""); + } + + XmTextFieldSetString(propWindow->aliasTextW,""); + XmTextFieldSetString(propWindow->processTextW,""); + XmTextFieldSetString(propWindow->sevrProcessTextW,""); + XmTextFieldSetString(propWindow->statProcessTextW,""); + XmTextSetString(propWindow->guidanceTextW, ""); + XmTextSetString(propWindow->guidanceUrlW, ""); + + return; + } + + pgcData = link->pgcData; + linkType =getSelectionLinkTypeArea(propWindow->area); + if (linkType == CHANNEL) pcData = (struct chanData *)pgcData; + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + if (linkType == GROUP) string = XmStringCreateSimple("Group "); + else string = XmStringCreateSimple("Channel"); + XtVaSetValues(propWindow->nameLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + + XmTextFieldSetString(propWindow->nameTextW, pgcData->name); + /* + if (strncmp(pgcData->name,"Unnamed",7)) + XmTextFieldSetString(propWindow->nameTextW, pgcData->name); + else + XmTextFieldSetString(propWindow->nameTextW, ""); + */ + + /* --------------------------------- + Current Alarm Mask + --------------------------------- */ + if (linkType == GROUP) awGetMaskString(((struct groupData *)pgcData)->mask,buff); + else alGetMaskString(pcData->curMask,buff); + string = XmStringCreateSimple(buff); + XtVaSetValues(propWindow->alarmMaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + + if (programId != ALH) { + if (linkType == GROUP) XtSetSensitive(propWindow->maskFrameW, FALSE); + else XtSetSensitive(propWindow->maskFrameW, TRUE); + + alSetMask(buff,&mask); + if (mask.Cancel == 1 ) + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[0],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[0],FALSE,TRUE); + if (mask.Disable == 1 ) + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[1],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[1],FALSE,TRUE); + if (mask.Ack == 1 ) + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[2],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[2],FALSE,TRUE); + if (mask.AckT == 1 ) + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[3],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[3],FALSE,TRUE); + if (mask.Log == 1 ) + XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[4],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->alarmMaskToggleButtonW[4],FALSE,TRUE); + } + + /* --------------------------------- + Reset Mask + --------------------------------- */ + if (programId == ALH ) { + if ( linkType == CHANNEL) { + alGetMaskString(pcData->defaultMask,buff); + string = XmStringCreateSimple(buff); + } else { + string = XmStringCreateSimple(""); + } + XtVaSetValues(propWindow->resetMaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + } + + /* --------------------------------- + Beep Severity + --------------------------------- */ + if(pgcData->beepSevr > 1) + XmTextFieldSetString(propWindow->beepSeverityValueTextW,alhAlarmSeverityString[pgcData->beepSevr]); + else XmTextFieldSetString(propWindow->beepSeverityValueTextW,alhAlarmSeverityString[1]); + + /* --------------------------------- + Severity Process Variable + --------------------------------- */ + if(strcmp(pgcData->sevrPVName,"-") != 0) + XmTextFieldSetString(propWindow->severityPVnameTextW,pgcData->sevrPVName); + else XmTextFieldSetString(propWindow->severityPVnameTextW,""); + + /* --------------------------------- + Alarm Count Filter + --------------------------------- */ + if (linkType == GROUP) { + XmTextFieldSetString(propWindow->countFilterCountTextW,""); + XmTextFieldSetString(propWindow->countFilterSecondsTextW,""); + XtVaSetValues(propWindow->countFilterCountTextW,XmNbackground,textBackgroundNS,NULL); + XtVaSetValues(propWindow->countFilterSecondsTextW,XmNbackground,textBackgroundNS,NULL); + } else { + XtVaSetValues(propWindow->countFilterCountTextW,XmNbackground,textBackground,NULL); + XtVaSetValues(propWindow->countFilterSecondsTextW,XmNbackground,textBackground,NULL); + if(pcData->countFilter) { + sprintf(buff,"%d",pcData->countFilter->inputCount); + XmTextFieldSetString(propWindow->countFilterCountTextW,buff); + sprintf(buff,"%d",pcData->countFilter->inputSeconds); + XmTextFieldSetString(propWindow->countFilterSecondsTextW,buff); + } else { + XmTextFieldSetString(propWindow->countFilterCountTextW,""); + XmTextFieldSetString(propWindow->countFilterSecondsTextW,""); + } + } + + /* --------------------------------- + Force Process Variable + --------------------------------- */ + if(pgcData->pforcePV && pgcData->pforcePV->name) + XmTextFieldSetString(propWindow->forcePVnameTextW,pgcData->pforcePV->name); + else XmTextFieldSetString(propWindow->forcePVnameTextW,""); + + if(pgcData->pforcePV){ + XmTextFieldSetString(propWindow->forcePVnameTextW,pgcData->pforcePV->name); + alGetMaskString(pgcData->pforcePV->forceMask,buff); + string = XmStringCreateSimple(buff); + } else string = XmStringCreateSimple("-----"); + XtVaSetValues(propWindow->forcePVForceMaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + if (programId != ALH) { + if(pgcData->pforcePV) mask = pgcData->pforcePV->forceMask; + if (mask.Cancel == 1 ) + XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[0],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[0],FALSE,TRUE); + if (mask.Disable == 1 ) + XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[1],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[1],FALSE,TRUE); + if (mask.Ack == 1 ) + XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[2],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[2],FALSE,TRUE); + if (mask.AckT == 1 ) + XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[3],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[3],FALSE,TRUE); + if (mask.Log == 1 ) + XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[4],TRUE,TRUE); + else XmToggleButtonSetState(propWindow->forceMaskToggleButtonW[4],FALSE,TRUE); + } + + if(pgcData->pforcePV){ + + sprintf(buff,"%g",pgcData->pforcePV->forceValue); + XmTextFieldSetString(propWindow->forcePVforceValueTextW,buff); + + sprintf(buff1,"%g",pgcData->pforcePV->resetValue); + if (!strcmp(buff,buff1)) sprintf(buff,"%s","NE"); + else strcpy(buff,buff1); + XmTextFieldSetString(propWindow->forcePVresetValueTextW,buff); + + if(pgcData->pforcePV->pcalc){ + if (pgcData->pforcePV->pcalc->expression) + XmTextFieldSetString(propWindow->forcePVCalcExpressionTextW, + pgcData->pforcePV->pcalc->expression); + else XmTextFieldSetString(propWindow->forcePVCalcExpressionTextW,""); + for (i=0;i<NO_OF_CALC_PVS;i++){ + if (pgcData->pforcePV->pcalc->name[i]) + XmTextFieldSetString(propWindow->forcePVCalcPVTextW[i], + pgcData->pforcePV->pcalc->name[i]); + else XmTextFieldSetString(propWindow->forcePVCalcPVTextW[i],""); + } + } else { + XmTextFieldSetString(propWindow->forcePVCalcExpressionTextW,""); + for (i=0;i<NO_OF_CALC_PVS;i++){ + XmTextFieldSetString(propWindow->forcePVCalcPVTextW[i],""); + } + } + } else { + /* ForcePV data */ + XmTextFieldSetString(propWindow->forcePVnameTextW,""); + string = XmStringCreateSimple("-----"); + XtVaSetValues(propWindow->forcePVForceMaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + XmTextFieldSetString(propWindow->forcePVforceValueTextW,""); + XmTextFieldSetString(propWindow->forcePVresetValueTextW,""); + XmTextFieldSetString(propWindow->forcePVCalcExpressionTextW,""); + for (i=0;i<NO_OF_CALC_PVS;i++){ + XmTextFieldSetString(propWindow->forcePVCalcPVTextW[i],""); + } + } + /* --------------------------------- + Alias + --------------------------------- */ + XmTextFieldSetString(propWindow->aliasTextW,pgcData->alias); + + /* --------------------------------- + Related Process Command + --------------------------------- */ + XmTextFieldSetString(propWindow->processTextW,pgcData->command); + + /* --------------------------------- + Sevr Command + --------------------------------- */ + getStringSevrCommandList(&pgcData->sevrCommandList,&str); + XmTextSetString(propWindow->sevrProcessTextW,str); + free(str); + + /* --------------------------------- + Stat Command + --------------------------------- */ + if (linkType == GROUP) { + XtSetSensitive(propWindow->statProcessTextW, FALSE); + XtVaSetValues(propWindow->statProcessTextW,XmNbackground,textBackgroundNS,NULL); + XmTextSetString(propWindow->statProcessTextW,""); + } else { + XtSetSensitive(propWindow->statProcessTextW, TRUE); + XtVaSetValues(propWindow->statProcessTextW,XmNbackground,textBackground,NULL); + getStringStatCommandList(&pcData->statCommandList,&str); + XmTextSetString(propWindow->statProcessTextW,str); + free(str); + } + + /* --------------------------------- + Guidance URL + --------------------------------- */ + XmTextFieldSetString(propWindow->guidanceUrlW,link->guidanceLocation); + + /* --------------------------------- + Guidance Text + --------------------------------- */ + pt = sllFirst(&(link->GuideList)); + i=0; + while (pt) { + guideLink = (struct guideLink *)pt; + i += strlen(guideLink->list); + i += 1; + pt = sllNext(pt); + } + str = (char*)calloc(i+1,sizeof(char)); + pt = sllFirst(&(link->GuideList)); + while (pt) { + guideLink = (struct guideLink *)pt; + strcat(str,guideLink->list); + pt = sllNext(pt); + if (pt) strcat(str,"\n"); + } + + XmTextSetString(propWindow->guidanceTextW, str); + free(str); + +} + +/****************************************************** + propCreateDialog +******************************************************/ +static void propCreateDialog(ALINK *area) +{ + struct propWindow *propWindow; + int n; + Arg args[10]; + + Widget propDialogShell, propDialog, severityPVnameTextW; + Widget beepSeverityValueTextW; + Widget rowcol, form, maskFrameW=0; + Widget nameLabelW, nameTextW; + Widget beepSeverityLabel, severityPVlabel; + Widget alarmMaskToggleButtonW[ALARM_NMASK]; + Widget forceMaskToggleButtonW[ALARM_NMASK]; + Widget aliasLabel, aliasTextW; + Widget processLabel, processTextW; + Widget sevrProcessLabel, sevrProcessTextW; + Widget statProcessLabel, statProcessTextW; + Widget forcePVcurrentValueTextW=0; + Widget forcePVLabel; + Widget forcePVnameLabel, forcePVnameTextW; + Widget forcePVForceMaskLabel; + Widget forcePVForceMaskStringLabelW; + Widget forcePVforceValueLabel, forcePVforceValueTextW; + Widget forcePVresetValueLabel, forcePVresetValueTextW; + Widget forcePVCalcLabel; + Widget forcePVCalcExpressionLabel, forcePVCalcExpressionTextW; + Widget forcePVCalcPVLabel[NO_OF_CALC_PVS], + forcePVCalcPVTextW[NO_OF_CALC_PVS]; + Widget frame2, form2, frame3, form3; + Widget guidanceLabel, guidanceTextW, + guidanceUrlLabel, guidanceUrlW; + Widget alarmMaskLabel, alarmMaskStringLabelW; + Widget resetMaskLabel=0, resetMaskStringLabelW=0; + Widget prev; + int i; + Widget countFilterFrame, form1, countFilterLabel, + countFilterCountLabel,countFilterCountTextW, + countFilterSecondsLabel, countFilterSecondsTextW; + Pixel textBackground; + XmString string; + char letter[]={"ABCDEF"}; + char pvid[]="A "; + static ActionAreaItem prop_items_act[] = { + { "Apply", propApplyCallback, NULL }, + { "Cancel", propCancelCallback, NULL }, + { "Dismiss", propDismissCallback, NULL }, + { "Help", propHelpCallback, NULL }, + }; + static ActionAreaItem prop_items_alh[] = { + { "Dismiss", propDismissCallback, NULL }, + { "Help", propHelpCallback, NULL }, + }; + static String maskFields[] = { + "Cancel Alarm", + "Disable Alarm", + "NoAck Alarm", + "NoAck Transient Alarm", + "NoLog Alarm" + }; + + if (!area) return; + + propWindow = (struct propWindow *)area->propWindow; + + if (propWindow && propWindow->propDialog){ + if (XtIsManaged(propWindow->propDialog)) return; + else XtManageChild(propWindow->propDialog); + } + + if (programId != ALH) textBackground = bg_pixel[3]; + else textBackground = bg_pixel[0]; + + propWindow = (struct propWindow *)calloc(1,sizeof(struct propWindow)); + area->propWindow = (void *)propWindow; + propWindow->area = (void *)area; + + propDialogShell = XtVaCreatePopupShell("Alarm Handler Properties", + transientShellWidgetClass, area->toplevel, NULL); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(propDialogShell, + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(propDialogShell), + "WM_DELETE_WINDOW", False); + XmAddWMProtocolCallback(propDialogShell,WM_DELETE_WINDOW, + (XtCallbackProc)propDismissCallback, (XtPointer)propWindow); + } + + propDialog = XtVaCreateWidget("propDialog", + xmPanedWindowWidgetClass, propDialogShell, + XmNsashWidth, 1, + XmNsashHeight, 1, + XmNuserData, area, + (XtPointer)NULL); + + (void)XtVaCreateWidget("control_area", xmRowColumnWidgetClass, propDialog, NULL); + form = XtVaCreateWidget("control_area", xmFormWidgetClass, propDialog, NULL); + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + nameLabelW = XtVaCreateManagedWidget("nameLabelW", + xmLabelGadgetClass, form, + XmNrecomputeSize, True, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + NULL); + + nameTextW = XtVaCreateManagedWidget("nameTextW", + xmTextFieldWidgetClass, form, + XmNspacing, 0, + XmNmarginHeight, 0, +/* + XmNcolumns, 30, + XmNrecomputeSize, True, +*/ + XmNmaxLength, PVNAME_SIZE, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, nameLabelW, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + NULL); + + XtAddCallback(nameTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + /* --------------------------------- + Current Alarm Mask + --------------------------------- */ + if (programId != ALH) string = XmStringCreateSimple("Alarm Mask "); + else string = XmStringCreateSimple("Current Mask "); + alarmMaskLabel = XtVaCreateManagedWidget("alarmMaskLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, nameTextW, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + prev = alarmMaskLabel; + + string = XmStringCreateSimple("-----"); + alarmMaskStringLabelW = XtVaCreateManagedWidget("alarmMaskStringLabelW", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, nameTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, alarmMaskLabel, + NULL); + XmStringFree(string); + + /* --------------------------------- + Reset Mask + --------------------------------- */ + if (programId == ALH ) { + string = XmStringCreateSimple("Reset Mask "); + resetMaskLabel = XtVaCreateManagedWidget("resetMaskLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNleftAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, alarmMaskLabel, + NULL); + XmStringFree(string); + prev = resetMaskLabel; + + string = XmStringCreateSimple(" "); + resetMaskStringLabelW = XtVaCreateManagedWidget("resetMaskStringLabelW", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, alarmMaskLabel, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, resetMaskLabel, + NULL); + XmStringFree(string); + } + + if (programId != ALH) { + maskFrameW = XtVaCreateManagedWidget("maskFrameW", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_FORM, + NULL); + prev=maskFrameW; + + rowcol = XtVaCreateWidget("rowcol", + xmRowColumnWidgetClass, maskFrameW, + XmNspacing, 0, + XmNmarginHeight, 0, + NULL); + + for (i = 0; i < ALARM_NMASK; i++){ + long ilong=i; + alarmMaskToggleButtonW[i] = XtVaCreateManagedWidget(maskFields[i], + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNuserData, (XtPointer)alarmMaskStringLabelW, + NULL); + XtAddCallback(alarmMaskToggleButtonW[i], XmNvalueChangedCallback, + (XtCallbackProc)propMaskChangeCallback, (XtPointer)ilong); + } + + XtManageChild(rowcol); + } + + /* --------------------------------- + Alarm Count Filter + --------------------------------- */ + countFilterFrame = XtVaCreateManagedWidget("countFilterFrame", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 50, + NULL); + + form1 = XtVaCreateWidget("form1", + xmFormWidgetClass, countFilterFrame, + XmNspacing, 0, + XmNmarginHeight, 0, + NULL); + + string = XmStringCreateSimple("Alarm Count Filter "); + countFilterLabel = XtVaCreateManagedWidget("countFilterLabel", + xmLabelGadgetClass, form1, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple("Count "); + countFilterCountLabel = XtVaCreateManagedWidget("countFilterCountLabel", + xmLabelGadgetClass, form1, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, countFilterLabel, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + countFilterCountTextW = XtVaCreateManagedWidget("countFilterCountTextW", + xmTextFieldWidgetClass, form1, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 3, + XmNmaxLength, 3, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, countFilterLabel, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, countFilterCountLabel, + NULL); + + XtAddCallback(countFilterCountTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + string = XmStringCreateSimple("Seconds "); + countFilterSecondsLabel = XtVaCreateManagedWidget("countFilterSecondsLabel", + xmLabelGadgetClass, form1, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, countFilterLabel, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, countFilterCountTextW, + NULL); + XmStringFree(string); + + countFilterSecondsTextW = XtVaCreateManagedWidget("countFilterSecondsTextW", + xmTextFieldWidgetClass, form1, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 3, + XmNmaxLength, 3, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, countFilterLabel, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, countFilterSecondsLabel, + NULL); + + XtAddCallback(countFilterSecondsTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + /* Form is full -- now manage */ + XtManageChild(form1); + + /* --------------------------------- + Force Process Variable + --------------------------------- */ + + frame2 = XtVaCreateManagedWidget("frame2", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + form2 = XtVaCreateWidget("form2", + xmFormWidgetClass, frame2, + XmNspacing, 0, + XmNmarginHeight, 0, + NULL); + + string = XmStringCreateSimple("Force Process Variable"); + forcePVLabel = XtVaCreateManagedWidget("forcePVLabel", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple("PV Name "); + forcePVnameLabel = XtVaCreateManagedWidget("forcePVnameLabel", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVLabel, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + forcePVnameTextW = XtVaCreateManagedWidget("forcePVnameTextW", + xmTextFieldWidgetClass, form2, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 30, + XmNmaxLength, PVNAME_SIZE, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVLabel, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVnameLabel, + NULL); + + XtAddCallback(forcePVnameTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + string = XmStringCreateSimple("Force Mask "); + forcePVForceMaskLabel = XtVaCreateManagedWidget("forcePVForceMaskLabel", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVnameTextW, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + prev = forcePVForceMaskLabel; + + string = XmStringCreateSimple("-----"); + forcePVForceMaskStringLabelW = XtVaCreateManagedWidget("forcePVmaskStringLabelW", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVnameTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVForceMaskLabel, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple(" Force Value "); + forcePVforceValueLabel = XtVaCreateManagedWidget("forcePVvalue", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVnameTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVForceMaskStringLabelW, + NULL); + XmStringFree(string); + + forcePVforceValueTextW = XtVaCreateManagedWidget("forcePVforceValueTextW", + xmTextFieldWidgetClass, form2, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 8, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVnameTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVforceValueLabel, + NULL); + + XtAddCallback(forcePVforceValueTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + string = XmStringCreateSimple(" Reset Value "); + forcePVresetValueLabel = XtVaCreateManagedWidget("forcePVresetValueLabel", + xmLabelGadgetClass, form2, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVnameTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVforceValueTextW, + NULL); + XmStringFree(string); + + forcePVresetValueTextW = XtVaCreateManagedWidget("forcePVresetValueTextW", + xmTextFieldWidgetClass, form2, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 8, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVnameTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVresetValueLabel, + NULL); + + XtAddCallback(forcePVresetValueTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + frame3 = XtVaCreateManagedWidget("frame3", + xmFrameWidgetClass, form2, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, forcePVforceValueTextW, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + form3 = XtVaCreateWidget("form2", + xmFormWidgetClass, frame3, + XmNspacing, 0, + XmNmarginHeight, 0, + NULL); + + string = XmStringCreateSimple("Force CALC"); + forcePVCalcLabel = XtVaCreateManagedWidget("forcePVCalcLabel", + xmLabelGadgetClass, form3, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple(" Expression "); + forcePVCalcExpressionLabel = XtVaCreateManagedWidget("forcePVCalcExpression", + xmLabelGadgetClass, form3, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVCalcLabel, + NULL); + XmStringFree(string); + + forcePVCalcExpressionTextW = XtVaCreateManagedWidget("forcePVCalcExpressionTextW", + xmTextFieldWidgetClass, form3, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 40, + XmNmaxLength, 100, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVCalcExpressionLabel, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtAddCallback(forcePVforceValueTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + prev = forcePVCalcExpressionTextW; + + for (i=0;i<NO_OF_CALC_PVS/2;i++) { + + pvid[0]=letter[i]; + string = XmStringCreateSimple(pvid); + forcePVCalcPVLabel[i] = XtVaCreateManagedWidget("forcePVCalcPVLabel", + xmLabelGadgetClass, form3, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + forcePVCalcPVTextW[i] = XtVaCreateManagedWidget("forcePVCalcPVTextW", + xmTextFieldWidgetClass, form3, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 30, + XmNmaxLength, PVNAME_SIZE, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVCalcPVLabel[i], + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + NULL); + + prev = forcePVCalcPVTextW[i]; + + XtAddCallback(forcePVCalcPVTextW[i], XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + } + + prev = forcePVCalcExpressionTextW; + + for (i=NO_OF_CALC_PVS/2;i<NO_OF_CALC_PVS;i++) { + + pvid[0]=letter[i]; + string = XmStringCreateSimple(pvid); + forcePVCalcPVLabel[i] = XtVaCreateManagedWidget("forcePVCalcPVLabel", + xmLabelGadgetClass, form3, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 50, +/* + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVCalcPVTextW[i-6], +*/ + NULL); + XmStringFree(string); + + forcePVCalcPVTextW[i] = XtVaCreateManagedWidget("forcePVCalcPVTextW", + xmTextFieldWidgetClass, form3, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 30, + XmNmaxLength, PVNAME_SIZE, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, prev, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, forcePVCalcPVLabel[i], + XmNrightAttachment, XmATTACH_FORM, + NULL); + + prev = forcePVCalcPVTextW[i]; + + + XtAddCallback(forcePVCalcPVTextW[i], XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + } + + /* RowColumn is full -- now manage */ + XtManageChild(form3); + + /* RowColumn is full -- now manage */ + XtManageChild(form2); + + /* ---------------- + Beep Severity + -------------- */ + string = XmStringCreateSimple("Beep Severity "); + beepSeverityLabel = XtVaCreateManagedWidget("beepSeverityLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, frame2, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + beepSeverityValueTextW = XtVaCreateManagedWidget("beepSeverityValueTextW", + xmTextFieldWidgetClass, form, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNcolumns, 10, + XmNmaxLength, 10, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, frame2, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, beepSeverityLabel, + NULL); + + XtAddCallback(beepSeverityValueTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + /* --------------------------------- + Severity Process Variable + --------------------------------- */ + string = XmStringCreateSimple("Severity PV Name"); + severityPVlabel = XtVaCreateManagedWidget("severityPVlabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, beepSeverityValueTextW, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + severityPVnameTextW = XtVaCreateManagedWidget("severityPVnameTextW", + xmTextFieldWidgetClass, form, + XmNspacing, 0, + XmNmarginHeight, 0, +/* + XmNcolumns, 30, + XmNmaxLength, PVNAME_SIZE, +*/ + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, beepSeverityValueTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, severityPVlabel, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtAddCallback(severityPVnameTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + /* --------------------------------- + Alias + --------------------------------- */ + string = XmStringCreateSimple("Alias"); + aliasLabel = XtVaCreateManagedWidget("aliasLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, severityPVnameTextW, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + /*XmNcolumns, 80,*/ + + aliasTextW = XtVaCreateManagedWidget("aliasTextW", + xmTextFieldWidgetClass, form, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, severityPVnameTextW, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, aliasLabel, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtAddCallback(aliasTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + /* --------------------------------- + Related Process Command + --------------------------------- */ + string = XmStringCreateSimple("Related Process Command"); + processLabel = XtVaCreateManagedWidget("processLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, aliasLabel, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + processTextW = XtVaCreateManagedWidget("processTextW", + xmTextFieldWidgetClass, form, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, processLabel, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtAddCallback(processTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + /* --------------------------------- + Sevr Command + --------------------------------- */ + string = XmStringCreateSimple("Alarm Severity Commands"); + sevrProcessLabel = XtVaCreateManagedWidget("sevrProcessLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, processTextW, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + /* Create Scrolled Text */ + n=0; + XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); + n++; + XtSetArg(args[n], XmNbackground, textBackground); + n++; + XtSetArg(args[n], XmNrows, 2); + n++; + sevrProcessTextW = XmCreateScrolledText(form,"sevrProcessTextW",args,n); + + XtVaSetValues(XtParent(sevrProcessTextW), + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, sevrProcessLabel, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtManageChild(sevrProcessTextW); + + /* --------------------------------- + Stat Command + --------------------------------- */ + string = XmStringCreateSimple("Alarm Status Commands"); + statProcessLabel = XtVaCreateManagedWidget("statProcessLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, XtParent(sevrProcessTextW), + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + /* Create Scrolled Text */ + n=0; + XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); + n++; + XtSetArg(args[n], XmNbackground, textBackground); + n++; + XtSetArg(args[n], XmNrows, 2); + n++; + statProcessTextW = XmCreateScrolledText(form,"statProcessTextW",args,n); + + XtVaSetValues(XtParent(statProcessTextW), + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, statProcessLabel, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtManageChild(statProcessTextW); + + /* --------------------------------- + Guidance URL Location + --------------------------------- */ + string = XmStringCreateSimple("Guidance URL"); + guidanceUrlLabel = XtVaCreateManagedWidget("guidanceUrlLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, XtParent(statProcessTextW), + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + guidanceUrlW = XtVaCreateManagedWidget("guidanceUrlW", + xmTextFieldWidgetClass, form, + XmNspacing, 0, + XmNmarginHeight, 0, + XmNbackground, textBackground, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, guidanceUrlLabel, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + XtAddCallback(processTextW, XmNactivateCallback, + (XtCallbackProc)XmProcessTraversal, (XtPointer)XmTRAVERSE_NEXT_TAB_GROUP); + + /* --------------------------------- + Guidance Text + --------------------------------- */ + string = XmStringCreateSimple("Guidance Text "); + guidanceLabel = XtVaCreateManagedWidget("guidanceLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, guidanceUrlW, + XmNleftAttachment, XmATTACH_FORM, + NULL); + XmStringFree(string); + + /* Create Scrolled Text */ + n=0; + XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); + n++; + XtSetArg(args[n], XmNbackground, textBackground); + n++; + XtSetArg(args[n], XmNrows, 6); + n++; + /*XtSetArg(args[n], XmNcursorPositionVisible, True); n++; */ + /*XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++; */ + guidanceTextW = XmCreateScrolledText(form,"guidanceTextW",args,n); + + XtVaSetValues(XtParent(guidanceTextW), + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, guidanceLabel, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + NULL); + + XtManageChild(guidanceTextW); + + if (programId != ALH) { + /* Set the client data "Apply", "Cancel", "Dismiss" and "Help" button's callbacks. */ + prop_items_act[0].data = (XtPointer)propWindow; + prop_items_act[1].data = (XtPointer)propWindow; + prop_items_act[2].data = (XtPointer)propWindow; + prop_items_act[3].data = (XtPointer)propWindow; + + (void)createActionButtons(propDialog, prop_items_act, XtNumber(prop_items_act)); + } else { + prop_items_alh[0].data = (XtPointer)propWindow; + prop_items_alh[1].data = (XtPointer)propWindow; + + (void)createActionButtons(propDialog, prop_items_alh, XtNumber(prop_items_alh)); + } + + XtManageChild(form); + XtManageChild(propDialog); + + propWindow->propDialog = propDialog; + propWindow->nameLabelW = nameLabelW; + propWindow->nameTextW = nameTextW; + propWindow->alarmMaskStringLabelW = alarmMaskStringLabelW; + propWindow->resetMaskStringLabelW = resetMaskStringLabelW; + propWindow->maskFrameW = maskFrameW; + propWindow->beepSeverityValueTextW = beepSeverityValueTextW; + propWindow->severityPVnameTextW = severityPVnameTextW; + propWindow->countFilterFrame = countFilterFrame; + propWindow->countFilterCountTextW = countFilterCountTextW; + propWindow->countFilterSecondsTextW = countFilterSecondsTextW; + propWindow->forcePVnameTextW = forcePVnameTextW; + propWindow->forcePVForceMaskStringLabelW = forcePVForceMaskStringLabelW; + propWindow->forcePVcurrentValueTextW = forcePVcurrentValueTextW; + propWindow->forcePVforceValueTextW = forcePVforceValueTextW; + propWindow->forcePVresetValueTextW = forcePVresetValueTextW; + propWindow->forcePVCalcExpressionTextW = forcePVCalcExpressionTextW; + for (i=0;i<NO_OF_CALC_PVS;i++) { + propWindow->forcePVCalcPVTextW[i] = forcePVCalcPVTextW[i]; + } + propWindow->aliasTextW = aliasTextW; + propWindow->processTextW = processTextW; + propWindow->sevrProcessTextW = sevrProcessTextW; + propWindow->statProcessTextW = statProcessTextW; + propWindow->guidanceTextW = guidanceTextW; + propWindow->guidanceUrlW = guidanceUrlW; + if (programId != ALH) { + for (i = 0; i < ALARM_NMASK; i++){ + propWindow->alarmMaskToggleButtonW[i] = alarmMaskToggleButtonW[i]; + propWindow->forceMaskToggleButtonW[i] = forceMaskToggleButtonW[i]; + } + } + + /* update propWindow link info */ + propEditableDialogWidgets(area); + + XtRealizeWidget(propDialogShell); + +} + +/****************************************************** + propMaskChangeCallback +******************************************************/ +static void propMaskChangeCallback( Widget widget,XtPointer calldata,XtPointer cbs) +{ + int index=(long)calldata; + char *mask; + Widget maskWidget; + XmString string; + + XtVaGetValues(widget, XmNuserData, &maskWidget, NULL); + + XtVaGetValues(maskWidget, XmNlabelString, &string, NULL); + XmStringGetLtoR(string, XmFONTLIST_DEFAULT_TAG, &mask); + XmStringFree(string); + + if (!XmToggleButtonGadgetGetState(widget)) { + mask[index] = '-'; + } + else { + switch (index) { + case ALARMCANCEL: + mask[index] = 'C'; + break; + case ALARMDISABLE: + mask[index] = 'D'; + break; + case ALARMACK: + mask[index] = 'A'; + break; + case ALARMACKT: + mask[index] = 'T'; + break; + case ALARMLOG: + mask[index] = 'L'; + break; + } + } + + string = XmStringCreateSimple(mask); + XtVaSetValues(maskWidget, XmNlabelString, string, NULL); + XmStringFree(string); + XtFree(mask); +} + +/****************************************************** + propApplyCallback +******************************************************/ +static void propApplyCallback( Widget widget,XtPointer calldata,XtPointer cbs) +{ + struct propWindow *propWindow=(struct propWindow *)calldata; + short f1, f2; + double dbl; + int i, rtn, rtn2; + struct anyLine *line; + struct chanData *cdata; + XmString string; + char *buff; + struct gcData *pgcData; + GCLINK *link; + int linkType; + MASK mask; + struct guideLink *guideLink; + FORCEPV_CALC* pcalc; + + /* PROPERTY UNDO WORKS BUT NOT IMPLEMENTED YET + GCLINK *undoLink=NULL; + int undoLinkType; + + editUndoGet(&undoLink, &linkType, &link); + */ + + link =getSelectionLinkArea(propWindow->area); + if (!link) return; + linkType =getSelectionLinkTypeArea(propWindow->area); + pgcData = link->pgcData; + + /* PROPERTY UNDO WORKS BUT NOT IMPLEMENTED YET + propDeleteClone(undoLink,undoLinkType); + undoLink = propCreateClone(link,linkType); + undoLinkType = linkType; + */ + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + buff = XmTextFieldGetString(propWindow->nameTextW); + pgcData->name = buff; + + /* --------------------------------- + Alarm Mask + --------------------------------- */ + if (linkType == CHANNEL) { + XtVaGetValues(propWindow->alarmMaskStringLabelW, XmNlabelString, &string, NULL); + XmStringGetLtoR(string,XmFONTLIST_DEFAULT_TAG,&buff); + XmStringFree(string); + cdata = (struct chanData *)pgcData; + alSetMask(buff,&mask); + XtFree(buff); + alChangeChanMask((CLINK *)link,mask); + if (programId != ALH) cdata->defaultMask = cdata->curMask; + } + + /* --------------------------------- + Beep Severity + --------------------------------- */ + buff = XmTextFieldGetString(propWindow->beepSeverityValueTextW); + pgcData->beepSevr = 0; + if (strlen(buff)) { + for (i=1; i<ALH_ALARM_NSEV; i++) { + if (strncmp(buff,alhAlarmSeverityString[i], + strlen(alhAlarmSeverityString[i]))==0){ + pgcData->beepSevr = i; + } + } + } + + + /* --------------------------------- + Severity Process Variable + --------------------------------- */ + buff = XmTextFieldGetString(propWindow->severityPVnameTextW); + if (strlen(buff)) pgcData->sevrPVName = buff; + else pgcData->sevrPVName = "-"; + + /* --------------------------------- + Alarm Count Filter + --------------------------------- */ + if (linkType == CHANNEL) { + cdata = (struct chanData *)pgcData; + if (cdata->countFilter){ + if (cdata->countFilter->alarmTimeHistory){ + free(cdata->countFilter->alarmTimeHistory); + } + free(cdata->countFilter); + cdata->countFilter = 0; + } + buff = XmTextFieldGetString(propWindow->countFilterCountTextW); + rtn = sscanf(buff,"%hd",&f1); + buff = XmTextFieldGetString(propWindow->countFilterCountTextW); + rtn2 = sscanf(buff,"%hd",&f2); + if (rtn == 1 || rtn2 ==1 ){ + cdata->countFilter = (COUNTFILTER *)calloc(1,sizeof(COUNTFILTER)); + cdata->countFilter->clink=link; + if (rtn == 1 ) cdata->countFilter->inputCount = f1; + else cdata->countFilter->inputCount = 1; + if (rtn2 == 1 ) cdata->countFilter->inputSeconds = f2; + else cdata->countFilter->inputSeconds = 1; + if (cdata->countFilter->inputCount) cdata->countFilter->alarmTimeHistory = + (time_t *)calloc(2*cdata->countFilter->inputCount,sizeof(time_t)); + } + } + + /* --------------------------------- + Force Process Variable + --------------------------------- */ + if (!pgcData->pforcePV) pgcData->pforcePV=(FORCEPV*)calloc(1,sizeof(FORCEPV)); + /* update link field - pforcePV->name */ + buff = XmTextFieldGetString(propWindow->forcePVnameTextW); + if (pgcData->pforcePV->name) free(pgcData->pforcePV->name); + if (strlen(buff)) pgcData->pforcePV->name = buff; + else pgcData->pforcePV->name = 0; + + /* update link field - forcePVMask */ + XtVaGetValues(propWindow->forcePVForceMaskStringLabelW, XmNlabelString, &string, NULL); + XmStringGetLtoR(string,XmFONTLIST_DEFAULT_TAG,&buff); + XmStringFree(string); + alSetMask(buff,&(pgcData->pforcePV->forceMask)); + XtFree(buff); + + /* update link field - pforcePV->forceValue */ + buff = XmTextFieldGetString(propWindow->forcePVforceValueTextW); + dbl=0.0; + rtn = sscanf(buff,"%lf",&dbl); + if (rtn == 1) pgcData->pforcePV->forceValue = dbl; + else pgcData->pforcePV->forceValue = 1; + + /* update link field - pforcePV->resetValue */ + buff = XmTextFieldGetString(propWindow->forcePVresetValueTextW); + if (strncmp(buff,"NE",2)==0 || strncmp(buff,"ne",2)==0){ + pgcData->pforcePV->resetValue = pgcData->pforcePV->forceValue; + } else { + dbl=0.0; + rtn = sscanf(buff,"%lf",&dbl); + if (rtn == 1) pgcData->pforcePV->resetValue = dbl; + else pgcData->pforcePV->resetValue = 0; + } + + if (!pgcData->pforcePV->pcalc) + pgcData->pforcePV->pcalc=(FORCEPV_CALC*)calloc(1,sizeof(FORCEPV_CALC)); + pcalc=pgcData->pforcePV->pcalc; + + buff = XmTextFieldGetString(propWindow->forcePVCalcExpressionTextW); + if (pcalc->expression) free(pcalc->expression); + if (strlen(buff)) pcalc->expression = buff; + else pcalc->expression = 0; + + for (i=0;i<NO_OF_CALC_PVS;i++) { + buff = XmTextFieldGetString(propWindow->forcePVCalcPVTextW[i]); + if (pcalc->name[i]) free(pcalc->name[i]); + if (strlen(buff)) pcalc->name[i] = buff; + else pcalc->name[i] = 0; + } + + /* --------------------------------- + Alias + --------------------------------- */ + buff = XmTextFieldGetString(propWindow->aliasTextW); + if (strlen(buff)) pgcData->alias = buff; + else pgcData->alias = 0; + + /* --------------------------------- + Related Process Command + --------------------------------- */ + buff = XmTextFieldGetString(propWindow->processTextW); + if (strlen(buff)) pgcData->command = buff; + else pgcData->command = 0; + + /* --------------------------------- + Sevr Commands + --------------------------------- */ + ellInit(&(pgcData->sevrCommandList)); + + buff = XmTextGetString(propWindow->sevrProcessTextW); + if (strlen(buff)){ + while (TRUE) { + addNewSevrCommand(&pgcData->sevrCommandList,buff); + buff=strchr(buff,'\n'); + if ( !buff ) break; + *buff='\0'; + buff++; + } + } + + /* --------------------------------- + Stat Commands + --------------------------------- */ + if (linkType == CHANNEL) { + cdata = (struct chanData *)pgcData; + ellInit(&(cdata->statCommandList)); + + buff = XmTextGetString(propWindow->statProcessTextW); + if (strlen(buff)){ + while (TRUE) { + addNewStatCommand(&cdata->statCommandList,buff); + buff=strchr(buff,'\n'); + if ( !buff ) break; + *buff='\0'; + buff++; + } + } + } + + /* --------------------------------- + Guidance URL + --------------------------------- */ + buff = XmTextFieldGetString(propWindow->guidanceUrlW); + if (strlen(buff)) link->guidanceLocation = buff; + else link->guidanceLocation = 0; + + /* --------------------------------- + Guidance Text + --------------------------------- */ + sllInit(&(link->GuideList)); + + buff = XmTextGetString(propWindow->guidanceTextW); + if (strlen(buff)){ + while (TRUE) { + guideLink = (struct guideLink *)calloc(1,sizeof(struct guideLink)); + guideLink->list=buff; + sllAdd(&(link->GuideList),(SNODE *)guideLink); + buff=strchr(buff,'\n'); + if ( !buff ) break; + *buff='\0'; + buff++; + } + } + + /* --------------------------------- + Update dialog windows + --------------------------------- */ + /* update properties dialog window field */ + axUpdateDialogs(propWindow->area); + + /* update group line data and tree window */ + line = link->lineGroupW; + if (line && line->link==link ){ + line->pname = ((GCLINK *)link)->pgcData->name; + if (((GCLINK *)link)->pgcData->alias){ + line->alias = ((GCLINK *)link)->pgcData->alias; + } else { + line->alias = ((GCLINK *)link)->pgcData->name; + } + markSelectedWidget(((ALINK *)propWindow->area)->groupWindow, 0); + awRowWidgets(line, propWindow->area); + markSelectedWidget( ((ALINK *)propWindow->area)->groupWindow, ((WLINE *)line->wline)->name); + } + + /* update tree line data and group window */ + line = link->lineTreeW; + if (line && line->link==link ){ + line->pname = ((GCLINK *)link)->pgcData->name; + if (((GCLINK *)link)->pgcData->alias){ + line->alias = ((GCLINK *)link)->pgcData->alias; + } else { + line->alias = ((GCLINK *)link)->pgcData->name; + } + awRowWidgets(line, propWindow->area); + } + + /* --------------------------------- + set undo data + --------------------------------- */ + /* PROPERTY UNDO WORKS BUT NOT IMPLEMENTED YET + editUndoSet(undoLink,linkType, link, MENU_EDIT_UNDO_PROPERTIES, FALSE); + */ +} + +/****************************************************** + propHelpCallback +******************************************************/ +static void propHelpCallback( Widget widget,XtPointer calldata,XtPointer cbs) +{ + char *messageALH1 = + "This dialog window allows an operator to view the alarm properties\n" + "for a group or channel.\n" + " \n" + "Press the Dismiss button to close the Properties dialog window.\n" + "Press the Help button to get this help description window.\n" + ; + char * messageALH2 = " "; + + char *messageACT1 = + "This dialog window allows an operator to view and change alarm properties\n" + "for a group or channel.\n" + " \n" + "Press the Apply button to change the properties for the selected group or channel.\n" + "Press the Reset button to reset the properties to their initial values.\n" + "Press the Dismiss button to close the Properties dialog window.\n" + "Press the Help button to get this help description window.\n" + ; + char * messageACT2 = " "; + + if (programId == ALH) { + createDialog(widget,XmDIALOG_INFORMATION, messageALH1,messageALH2); + } else { + createDialog(widget,XmDIALOG_INFORMATION, messageACT1,messageACT2); + } + +} + +/****************************************************** + propDismissCallback +******************************************************/ +static void propDismissCallback( Widget widget,XtPointer calldata,XtPointer cbs) +{ + struct propWindow *propWindow=(struct propWindow *)calldata; + Widget propDialog; + + propDialog = propWindow->propDialog; + XtUnmanageChild(propDialog); + XUnmapWindow(XtDisplay(propDialog), XtWindow(XtParent(propDialog))); + if (propWindow->menuButton) + XtVaSetValues(propWindow->menuButton, XmNset, FALSE, NULL); +} + +/****************************************************** + propCancelCallback +******************************************************/ +static void propCancelCallback( Widget widget,XtPointer calldata,XtPointer cbs) +{ + struct propWindow *propWindow=(struct propWindow *)calldata; + propUpdateDialog((ALINK *)(propWindow->area)); +} + +/****************************************************** + propUndo +******************************************************/ +void propUndo(area) +void *area; +{ + GCLINK *link; + int linkType; + GCLINK *undoLink; + struct anyLine *line; + GCLINK *tempLink; + GLINK *glink; + CLINK *clink; + struct chanData *pchanData; + struct groupData *pgroupData; + + editUndoGet(&undoLink, &linkType, &link); + + if (!link) return; + tempLink = propCreateClone(link,linkType); + + if (linkType == GROUP) { + glink=(GLINK *)link; + pgroupData = glink->pgroupData; + *glink = *(GLINK*)undoLink; + *pgroupData = *(struct groupData *)undoLink->pgcData; + glink->pgroupData = pgroupData; + free((struct groupData *)undoLink->pgcData); + free((GLINK*)undoLink); + } + + if (linkType == CHANNEL) { + clink=(CLINK *)link; + pchanData = clink->pchanData; + *clink = *(CLINK *)undoLink; + *pchanData = *(struct chanData *)undoLink->pgcData; + clink->pchanData = pchanData; + free((struct chanData *)undoLink->pgcData); + free((CLINK*)undoLink); + } + undoLink = tempLink; + + /* --------------------------------- + Update dialog windows + --------------------------------- */ + axUpdateDialogs(area); + + /* --------------------------------- + Update tree line data and tree window + --------------------------------- */ + line = link->lineGroupW; + if (line && line->link==link ){ + line->pname = ((GCLINK *)link)->pgcData->name; + if (((GCLINK *)link)->pgcData->alias){ + line->alias = ((GCLINK *)link)->pgcData->alias; + } else { + line->alias = ((GCLINK *)link)->pgcData->name; + } + awRowWidgets(line,area); + } + + /* --------------------------------- + Update group line data and group window + --------------------------------- */ + line = link->lineTreeW; + if (line && line->link==link ){ + line->pname = ((GCLINK *)link)->pgcData->name; + if (((GCLINK *)link)->pgcData->alias){ + line->alias = ((GCLINK *)link)->pgcData->alias; + } else { + line->alias = ((GCLINK *)link)->pgcData->name; + } + awRowWidgets(line,area); + } + + /* --------------------------------- + set undo data + --------------------------------- */ + editUndoSet(undoLink,linkType, link, MENU_EDIT_UNDO_PROPERTIES, FALSE); + +} + +/****************************************************** + propEditableDialogWidgets +******************************************************/ +static void propEditableDialogWidgets(ALINK *area) +{ + struct propWindow *propWindow; + + propWindow = (struct propWindow *)area->propWindow; + + if (programId == ALH) { + XtVaSetValues(propWindow->nameTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->beepSeverityValueTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->severityPVnameTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->countFilterCountTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->countFilterSecondsTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->forcePVnameTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->forcePVforceValueTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->forcePVresetValueTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->aliasTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->processTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->sevrProcessTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->statProcessTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->guidanceTextW,XmNeditable, FALSE, NULL); + XtVaSetValues(propWindow->guidanceUrlW,XmNeditable, FALSE, NULL); + } else { + XtVaSetValues(propWindow->nameTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->beepSeverityValueTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->severityPVnameTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->countFilterCountTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->countFilterSecondsTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->forcePVnameTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->forcePVforceValueTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->forcePVresetValueTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->aliasTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->processTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->sevrProcessTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->statProcessTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->guidanceTextW,XmNeditable, TRUE, NULL); + XtVaSetValues(propWindow->guidanceUrlW,XmNeditable, TRUE, NULL); + } + return; +} + +#if 0 +/****************************************************** + propDeleteClone +******************************************************/ +static void propDeleteClone(GCLINK *link,int linkType) +{ + SNODE *pt,*next; + struct guideLink *guidelist; + struct gcData *pgcData; + struct chanData *pcData; + struct groupData *pgData; + + if (link == NULL) return; + + pgcData = link->pgcData; + if (pgcData->name) free(pgcData->name); + if (pgcData->pforcePV) alForcePVDelete(&pgcData->pforcePV); + if (strcmp(pgcData->sevrPVName,"-") != 0) free(pgcData->sevrPVName); + if (pgcData->command) free(pgcData->command); + if (pgcData->alias) free(pgcData->alias); + removeSevrCommandList(&pgcData->sevrCommandList); + if (linkType == CHANNEL) { + pcData = (struct chanData *)pgcData; + if (pcData->countFilter){ + if (pcData->countFilter->alarmTimeHistory){ + free(pcData->countFilter->alarmTimeHistory); + } + free(pcData->countFilter); + pcData->countFilter = 0; + } + removeStatCommandList(&pcData->statCommandList); + } + if (linkType == GROUP) { + pgData = (struct groupData *)pgcData; + if (pgData->treeSym) free(pgData->treeSym); + } + + if (link->guidanceLocation) free(link->guidanceLocation); + + pt = sllFirst(&link->GuideList); + while (pt) { + next = sllNext(pt); + guidelist = (struct guideLink *)pt; + free(guidelist->list); + free(guidelist); + pt = next; + } + free(pgcData); + free(link); +} +#endif + +/****************************************************** + propCreateClone +******************************************************/ +static GCLINK *propCreateClone(GCLINK *link,int linkType) +{ + CLINK *newChan; + struct chanData *pchanData; + GLINK *newGroup; + struct groupData *pgroupData; + + /* pointer contents not copied */ + if (linkType == GROUP) { + newGroup = alCreateGroup(); + pgroupData = newGroup->pgroupData; + *newGroup = *(GLINK *)link; + *pgroupData = *(struct groupData *)link->pgcData; + newGroup->pgroupData = pgroupData; + return (GCLINK *)newGroup; + } + + if (linkType == CHANNEL) { + newChan = alCreateChannel(); + pchanData = newChan->pchanData; + *newChan = *(CLINK *)link; + *pchanData = *(struct chanData *)link->pgcData; + newChan->pchanData = pchanData; + return (GCLINK *)newChan; + } + return NULL; +} + diff --git a/scroll.c b/scroll.c new file mode 100644 index 0000000..6d66ce8 --- /dev/null +++ b/scroll.c @@ -0,0 +1,1717 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* Scroll.c */ + +/************************DESCRIPTION*********************************** + This file contains the routines for viewing the alarm + configuration, alarm log file and operator modification + log file. It uses scrolled text window to display the text. + Opened scrolled window also displays the most current + events recorded in log files. +**********************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> +#include <ctype.h> +#ifndef WIN32 +#include <dirent.h> +#endif + +#include <Xm/Xm.h> +#include <Xm/RowColumn.h> +#include <Xm/Form.h> +#include <Xm/LabelG.h> +#include <Xm/Protocols.h> +#include <Xm/PushB.h> +#include <Xm/ScrollBar.h> +#include <Xm/Text.h> +#include <Xm/PanedW.h> +#include <Xm/Label.h> +#include <Xm/ToggleB.h> +#include <Xm/RowColumn.h> +#include <Xm/TextF.h> +#include <X11/Intrinsic.h> +#include <X11/Xlib.h> +#include <X11/cursorfont.h> + +#include "alh.h" +#include "ax.h" + + +extern Display *display; +extern int _global_flag; +extern int _description_field_flag; + +#define MAX_NUM_OF_LOG_FILES 5000 /* # of log files for browser */ +static XmTextPosition positionSearch; +static int lenSearch; +extern char FS_filename[128]; /*FileName from FileSelectBox for AlLogV. */ + +static Widget findShell, findText; +static Widget text_with,text_fy,text_fmo,text_fd,text_fh,text_fmi, +text_ty,text_tmo,text_td,text_th,text_tmi; + +/* forward declarations */ +static void closeFileViewWindow_callback( Widget w, int operandFile, caddr_t call_data); +static void closeFileViewShell( Widget w, int operandFile, caddr_t call_data); +static void findForward(Widget,XtPointer,XtPointer); +static void findReverse(Widget,XtPointer,XtPointer); +static void findDismiss(Widget,XtPointer,XtPointer); +static void searchCallback(Widget,XtPointer,XmAnyCallbackStruct *); +static void allDigit(Widget,XtPointer,XmTextVerifyCallbackStruct *); +static void showAllCallback(Widget,XtPointer,XtPointer); +static void showSelectedCallback(Widget,XtPointer,XtPointer); +static void compactDataAscMonth(char *,char *,char *,char *,char *,char *); +static void compactData(char *,char *,char *,char *,char *,char *); +static char *digitalMonth(char *); +static Boolean extensionIsDate(char *); +char *Strncat( + char *dest, + const char *src, + int max ); + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? a : b) +#endif + + +static int viewFileUsedLength[N_LOG_FILES]; /* used length of file. */ +static int viewFileMaxLength[N_LOG_FILES]; /* max length of file. */ +static unsigned char *viewFileString[N_LOG_FILES]; /* contents of file. */ + +static Widget viewTextWidget[N_LOG_FILES] = {0,0,0}; /* view text widget */ +static Widget browserWidget; +static Widget viewFilenameWidget[N_LOG_FILES] = {0,0,0}; /* view filename widget */ + +extern int alarmLogFileOffsetBytes; /* alarm log file current offset in bytes */ +extern int alarmLogFileStringLength; /* alarm log file record length*/ +extern int alarmLogFileMaxRecords; /* alarm log file maximum # records */ + + +extern int DEBUG; +extern struct setup psetup; /* current file setup */ + +static char error_file_size[] = { + " Sorry: file size too big to view." + }; + + +typedef struct fplistTag { + struct fplistTag *flink; + struct fplistTag *blink; + FILE *f; +} fplistType, *fplistPtr; + +static fplistPtr g_head; + +#define MAXCONFIGFILELINE 1023 +#ifdef WIN32 +#define strtok_r strtok_s +#endif + +static void readFile ( + fplistPtr cur, + char *buf, + int *max, + int *size, + int *depth +) { + +char line[MAXCONFIGFILELINE+1], *result, *tk, *ctx, incFile[1023+1]; +fplistPtr new; +int i, l; + + if ( cur->f ) { + + do { + + result = fgets( line, MAXCONFIGFILELINE, cur->f ); + if ( result ) { + + *size += strlen(line) + *depth * 3; + + if ( *size+10 > *max ) { + *max = *size + 0.5 * *size; + buf = (char *) XtRealloc( buf, *max ); + } + + for ( i=0; i<*depth; i++ ) strcat( buf, " " ); + + strcat( buf, line ); + + ctx = NULL; + tk = strtok_r( line, " \t\n", &ctx ); + if ( tk ) { + if ( strcmp( tk, "INCLUDE" ) == 0 ) { + tk = strtok_r( NULL, " \t\n", &ctx ); + if ( tk ) { + tk = strtok_r( NULL, " \t\n", &ctx ); + if ( tk ) { + new = (fplistPtr) calloc( 1, sizeof(fplistType) ); + g_head->blink->flink = new; + new->blink = g_head->blink; + new->flink = g_head; + g_head->blink = new; + if ( psetup.configDir ) { + strncpy( incFile, psetup.configDir, 1023 ); + incFile[1023] = 0; + l = strlen( incFile ); + if ( l > 0 ) { + if ( incFile[l-1] != '/' ) { + Strncat( incFile, "/", 1023 ); + incFile[1023] = 0; + } + } + } + else { + strcpy( incFile, "" ); + } + Strncat( incFile, tk, 1023 ); + incFile[1023] = 0; + new->f = fopen( incFile, "r" ); + (*depth)++; + *size += strlen("----------------------------\n") + + *depth * 3; + if ( *size+10 > *max ) { + *max = *size + 0.5 * *size; + buf = (char *) XtRealloc( buf, *max ); + } + for ( i=0; i<*depth; i++ ) strcat( buf, " " ); + strcat( buf, "----------------------------\n" ); + readFile( new, buf, max, size, depth ); + *size += strlen("----------------------------\n") + *depth * 3; + if ( *size+10 > *max ) { + *max = *size + 0.5 * *size; + buf = (char *) XtRealloc( buf, *max ); + } + for ( i=0; i<*depth; i++ ) strcat( buf, " " ); + strcat( buf, "----------------------------\n" ); + (*depth)--; + if ( new->f ) fclose( new->f ); + new->blink->flink = new->flink; + new->flink->blink = new->blink; + free( new ); + } + } + } + } + + } + + } while ( result ); + + } + +} + +static void readAll ( + char *buf, + int max, + int num, + FILE *fp +) { + +fplistPtr cur; +int size = 0; +int depth = 0; + + g_head = (fplistPtr) calloc( 1, sizeof(fplistType) ); + g_head->f = NULL; + g_head->flink = g_head; + g_head->blink = g_head; + + cur = (fplistPtr) calloc( 1, sizeof(fplistType) ); + cur->f = fp; + + /* link */ + cur->blink = g_head->blink; + g_head->blink->flink = cur; + cur->flink = g_head; + g_head->blink = cur; + + readFile( cur, buf, &max, &size, &depth ); + + cur->blink->flink = cur->flink; + cur->flink->blink = cur->blink; + free( cur ); + + free( g_head ); + +} + +/************************************************************************** + create scroll window for file view +**************************************************************************/ +void fileViewWindow(Widget w,int option,Widget menuButton) +{ + static Widget config_shell=NULL,alarm_shell=NULL,opmod_shell=NULL; + Widget app_shell=NULL,title,button; + Widget previous; + struct stat statbuf; /* Information on a file. */ + FILE *fp = NULL; /* Pointer to open file. */ + char filename[120]; + int operandFile=0; + long operandFileLong; + Arg al[20]; + int ac; + XmString str=NULL; + + switch (option) { + case CONFIG_FILE: + operandFile = CONFIG_FILE; + app_shell = config_shell; + strcpy(filename,psetup.configFile); + break; + case ALARM_FILE: + operandFile = ALARM_FILE; + app_shell = alarm_shell; + strcpy(filename,psetup.logFile); + break; + case OPMOD_FILE: + operandFile = OPMOD_FILE; + app_shell = opmod_shell; + strcpy(filename,psetup.opModFile); + break; + } + if (app_shell && XtIsManaged(app_shell)) { + + viewFileUsedLength[option] = 0; + viewFileMaxLength[option] = 0; + + XtFree((char *)viewFileString[option]); + viewFileString[option]=NULL; + XtUnmanageChild(app_shell); + + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + + return; + } + + XtVaSetValues(menuButton, XmNset, TRUE, NULL); + + if (stat(filename, &statbuf) == 0) + viewFileUsedLength[operandFile] = statbuf.st_size; + else + viewFileUsedLength[operandFile] = 1000000; /* arbitrary file length */ + + if (statbuf.st_size > 1000000) + { + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + createDialog(XtParent(w),XmDIALOG_ERROR,filename, &error_file_size[0]); + return; + } + + /* allocate space for the file string */ + viewFileMaxLength[operandFile] = MAX(INITIAL_FILE_LENGTH, + 2*viewFileUsedLength[operandFile]); + viewFileString[operandFile] = (unsigned char *) + XtCalloc(1,(unsigned)viewFileMaxLength[operandFile]); + if(!viewFileString[operandFile]) { + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + createDialog(XtParent(w),XmDIALOG_ERROR,"no free memory",""); + return; + } + + /* read the file string */ + if ((fp = fopen(filename, "r")) == NULL) { + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + fprintf(stderr,"fileViewWindow: file %s not found\n",filename); + return; /* bail out if no file found */ + } + + switch (option) { + + case CONFIG_FILE: + readAll( viewFileString[operandFile], + viewFileUsedLength[operandFile], 1, fp ); + break; + + default: + fread(viewFileString[operandFile], + viewFileUsedLength[operandFile],1, fp); + break; + + } + + clearerr(fp); + if (fclose(fp)) fprintf(stderr, + "fileViewWindow: unable to close file %s.\n",filename); + + /* create view window dialog */ + if (!app_shell) { + ac = 0; + XtSetArg (al[ac], XmNy, 47); + ac++; + XtSetArg (al[ac], XmNx, 77); + ac++; + /* + XtSetArg (al[ac], XmNallowShellResize, FALSE); ac++; + */ + XtSetArg (al[ac], XmNallowOverlap, FALSE); + ac++; + XtSetArg(al[ac], XmNautoUnmanage, FALSE); + ac++; + switch (option) { + case CONFIG_FILE: + str = XmStringLtoRCreate("Configuration File", XmSTRING_DEFAULT_CHARSET); + break; + case ALARM_FILE: + str = XmStringLtoRCreate("Alarm Log File", XmSTRING_DEFAULT_CHARSET); + break; + case OPMOD_FILE: + str = XmStringLtoRCreate("Operator Mod File", XmSTRING_DEFAULT_CHARSET); + break; + } + XtSetArg(al[ac], XmNdialogTitle, str); + ac++; + app_shell = XmCreateFormDialog(XtParent(w), "SCROLL", al, ac); + XmStringFree(str); + XtVaSetValues(app_shell, XmNallowOverlap, FALSE, NULL); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(XtParent(app_shell), + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(XtParent(app_shell)), + "WM_DELETE_WINDOW", False); + operandFileLong=operandFile; + XmAddWMProtocolCallback(XtParent(app_shell),WM_DELETE_WINDOW, + (XtCallbackProc)closeFileViewShell, (XtPointer)operandFileLong); + } + + switch (option) { + case CONFIG_FILE: + config_shell = app_shell; + break; + case ALARM_FILE: + alarm_shell = app_shell; + break; + case OPMOD_FILE: + opmod_shell = app_shell; + break; + } + + /* add close button */ + ac = 0; + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNtopOffset, 5); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNleftOffset, 5); + ac++; + XtSetArg (al[ac], XmNuserData, menuButton); + ac++; + button = XtCreateManagedWidget("Close",xmPushButtonWidgetClass, + app_shell, al, ac); + operandFileLong=operandFile; + XtAddCallback(button, XmNactivateCallback, + (XtCallbackProc)closeFileViewWindow_callback, + (XtPointer) operandFileLong); + + previous = button; + /* create file name widget */ + ac = 0; + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNtopOffset, 6); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_WIDGET); + ac++; + XtSetArg (al[ac], XmNleftWidget, button); + ac++; + XtSetArg (al[ac], XmNleftOffset, 6); + ac++; + viewFilenameWidget[operandFile] = XtCreateManagedWidget(filename,xmLabelGadgetClass, + app_shell,al, ac); + + /* add titles */ + if ( option == ALARM_FILE) { + ac = 0; +/* + XtSetArg (al[ac], XmNwidth,800); + ac++; + XtSetArg (al[ac], XmNheight,30); + ac++; +*/ + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_WIDGET); + ac++; + XtSetArg (al[ac], XmNtopWidget, button); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM); + ac++; + if (!_description_field_flag) { + if (_global_flag) + title = XtCreateManagedWidget(" TIME_STAMP PROCESS_VARIABLE_NAME STATUS SEVERITY UNACK_SEV ACKT VALUE", + xmLabelGadgetClass,app_shell,al,ac); + else title = XtCreateManagedWidget(" TIME_STAMP PROCESS_VARIABLE_NAME STATUS SEVERITY VALUE", + xmLabelGadgetClass,app_shell,al,ac); + } else { /* _description_field_flag is ON */ + if (_global_flag) + title = XtCreateManagedWidget( +" TIME RECORD DESCRIPTION VALUE STATUS / SEVERITY / UNACK_SEV / ACKT", + xmLabelGadgetClass,app_shell,al,ac); + else title = XtCreateManagedWidget( +" TIME RECORD DESCRIPTION VALUE STATUS / SEVERITY", + xmLabelGadgetClass,app_shell,al,ac); + } + previous = title; + + } + + /* create text widget */ + ac = 0; + XtSetArg (al[ac], XmNrows, 24); + ac++; + XtSetArg (al[ac], XmNcolumns, 130); + ac++; + XtSetArg (al[ac], XmNscrollVertical, True); + ac++; + XtSetArg (al[ac], XmNscrollHorizontal, True); + ac++; + XtSetArg (al[ac], XmNeditMode, XmMULTI_LINE_EDIT); + ac++; + XtSetArg (al[ac], XmNeditable, FALSE); + ac++; + XtSetArg (al[ac], XmNcursorPositionVisible, FALSE); + ac++; + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_WIDGET); + ac++; + XtSetArg (al[ac], XmNtopWidget, previous); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNrightAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNbottomAttachment, XmATTACH_FORM); + ac++; + viewTextWidget[operandFile]=XmCreateScrolledText(app_shell, "text", al, ac); + + /* make appropriate item sensitive */ + XtSetSensitive(viewTextWidget[operandFile], True); + XmAddTabGroup(viewTextWidget[operandFile]); + + XtManageChild(viewTextWidget[operandFile]); + + } + /* update the file name string */ + str = XmStringLtoRCreate(filename, XmSTRING_DEFAULT_CHARSET); + XtVaSetValues(viewFilenameWidget[operandFile], XmNlabelString, str, NULL); + XmStringFree(str); + + /* add the file string to the text widget */ + XmTextSetString(viewTextWidget[operandFile], (char *)viewFileString[operandFile]); + + if (operandFile == ALARM_FILE && alarmLogFileOffsetBytes ) { + XtVaSetValues(viewTextWidget[operandFile], + XmNcursorPosition, alarmLogFileOffsetBytes-1, + NULL); + XmTextShowPosition(viewTextWidget[operandFile], alarmLogFileOffsetBytes-1); + viewFileUsedLength[operandFile] = alarmLogFileOffsetBytes; + } else { + XtVaSetValues(viewTextWidget[operandFile], + XmNcursorPosition, viewFileUsedLength[operandFile]-1, + NULL); + XmTextShowPosition(viewTextWidget[operandFile], viewFileUsedLength[operandFile]-1); + } + + XtManageChild(app_shell); +} + +/************************************************************************** + close scroll window for file view +**************************************************************************/ +static void closeFileViewShell(Widget w,int operandFile,caddr_t call_data) +{ + Widget menuButton; + WidgetList children; + + XtVaGetValues(w, XmNchildren, &children, NULL); + XtUnmanageChild(children[0]); + XtVaGetValues(children[0], XmNchildren, &children, NULL); + XtVaGetValues(children[0], XmNuserData, &menuButton, NULL); + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + + viewFileUsedLength[operandFile] = 0; + viewFileMaxLength[operandFile] = 0; + + XtFree((char *)viewFileString[operandFile]); + viewFileString[operandFile]=NULL; +} + +/************************************************************************** + close scroll window for file view +**************************************************************************/ +static void closeFileViewWindow_callback(Widget w,int operandFile, +caddr_t call_data) +{ + Widget menuButton; + XtVaGetValues(w, XmNuserData, &menuButton, NULL); + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + + viewFileUsedLength[operandFile] = 0; + viewFileMaxLength[operandFile] = 0; + + + XtFree((char *)viewFileString[operandFile]); + viewFileString[operandFile]=NULL; + XtUnmanageChild(XtParent(w)); +} + +/****************************************************************** + updateLog in scroll window +*****************************************************************/ +void updateLog(int fileIndex,char *string) +{ +#if 0 + struct stat statbuf; /* Information on a file. */ + FILE *fp = NULL; /* Pointer to open file */ + char filename[120]; +#endif + char *tmp; + + int stringLength = strlen(string); + int oldUsedLength = viewFileUsedLength[fileIndex]; + + + if (viewTextWidget[fileIndex] == NULL) return; + + /* simply return if the file string does not exist */ + if (viewFileString[fileIndex] == NULL) return; + + if (viewFileUsedLength[fileIndex] + stringLength <= + viewFileMaxLength[fileIndex]) { + + /* string fits, insert */ + strcat((char *)viewFileString[fileIndex],string); + viewFileUsedLength[fileIndex] = viewFileUsedLength[fileIndex] + + stringLength; + XmTextReplace(viewTextWidget[fileIndex],oldUsedLength, + oldUsedLength,string); + + + } else { + + /* string doesn't fit - reallocate to get enough room */ + viewFileMaxLength[fileIndex] = MAX(INITIAL_FILE_LENGTH, + 2*viewFileMaxLength[fileIndex]); + tmp = (char *)XtCalloc(1,(unsigned)viewFileMaxLength[fileIndex]); + strcpy(tmp,(const char *)viewFileString[fileIndex]); + XtFree((char *)viewFileString[fileIndex]); + viewFileString[fileIndex] = (unsigned char*)tmp; + + if (viewFileUsedLength[fileIndex] + stringLength <= + viewFileMaxLength[fileIndex]) { + + /* string fits, insert */ + strcat((char *)viewFileString[fileIndex],string); + viewFileUsedLength[fileIndex] = viewFileUsedLength[fileIndex] + + stringLength; + XmTextReplace(viewTextWidget[fileIndex],oldUsedLength, + oldUsedLength,string); + } +#if 0 + switch(fileIndex) { + case ALARM_FILE: + strcpy(filename,psetup.logFile); + break; + case OPMOD_FILE: + strcpy(filename,psetup.opModFile); + break; + } + + if (stat(filename, &statbuf) == 0) + viewFileUsedLength[fileIndex] = statbuf.st_size; + else + viewFileUsedLength[fileIndex] = 1000000; /* arbitrary file length */ + + /* read the file string */ + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr,"updateLog: file %s open error.\n",filename); + return; /* bail out if no file found */ + } + fread(viewFileString[fileIndex], sizeof(char), + viewFileUsedLength[fileIndex], fp); + if (fclose(fp)) fprintf(stderr, + "updateLog: unable to close file %s.\n",filename); + + /* add the file string to the text widget */ + XmTextSetString(viewTextWidget[fileIndex], (char *)viewFileString[fileIndex]); +#endif + + } + + XtVaSetValues(viewTextWidget[fileIndex], + XmNcursorPosition, viewFileUsedLength[fileIndex]-1, + NULL); + XmTextShowPosition(viewTextWidget[fileIndex], viewFileUsedLength[fileIndex]-1); + +} + + +/****************************************************************** + updateAlarmLog in scroll window +*****************************************************************/ +void updateAlarmLog(int fileIndex,char *string) +{ + updateLog(fileIndex,string); + +#if 0 + char str[MAX_STRING_LENGTH]; + int stringLength = strlen(string); + int startPosition,endPosition; + int pos=0; + + if (viewTextWidget[fileIndex] == NULL) return; + + XtVaGetValues(viewTextWidget[fileIndex], XmNcursorPosition, &pos, NULL); + + /* simply return if the file string does not exist */ + if (viewFileString[fileIndex] == NULL) return; + + if (viewFileUsedLength[fileIndex] + stringLength <= + viewFileMaxLength[fileIndex]) + { + /* put string at end */ + strcat((char *)viewFileString[fileIndex],string); + viewFileUsedLength[fileIndex] = viewFileUsedLength[fileIndex] + stringLength; + XmTextSetString(viewTextWidget[fileIndex], (char *)viewFileString[fileIndex]); + + } else + { + startPosition=alarmLogFileOffsetBytes-alarmLogFileStringLength; + endPosition=alarmLogFileOffsetBytes; + XmTextReplace(viewTextWidget[fileIndex],startPosition, endPosition,string); + memset(str,' ',alarmLogFileStringLength); + startPosition=alarmLogFileOffsetBytes; + endPosition=alarmLogFileOffsetBytes+alarmLogFileStringLength; + XmTextReplace(viewTextWidget[fileIndex],startPosition, endPosition,str); + } + + XtVaSetValues(viewTextWidget[fileIndex], XmNcursorPosition, pos, NULL); + XmTextShowPosition(viewTextWidget[fileIndex],pos); +#endif +} + +/************************************************************************** + create scroll window for AlarmLog browser. +**************************************************************************/ +void browser_fileViewWindow(Widget w,int option,Widget menuButton) +{ + static Widget alarm_shell=NULL; + static Widget opmod_shell=NULL; + Widget app_shell=NULL,title=0,button,button1; + Widget previous; + char sbuf[120]; +#ifndef WIN32 + DIR *directory; +#endif + struct stat statbuf; /* Information on a file. */ + FILE *fp = NULL; /* Pointer to open file. */ + char filename[120]; + int operandFile=0; + long operandFileLong; + /* definitions for search widgets: */ + Arg al[20]; + int ac; + XmString str=NULL; + Dimension height, margin_height; + Widget findPane, findBox, findLabel, findButtonBox, + findForwardButton, findReverseButton, findDismissButton; + Widget rowcol1,rowcol2,showButton,showAllButton; + time_t timeofday; + struct tm *tms; + char buf[120]; + char defaultString_fy[5],defaultString_fmo[3],defaultString_fd[3],defaultString_fh[3]="00",defaultString_fmi[3]="00"; + char defaultString_ty[5],defaultString_tmo[3],defaultString_td[3],defaultString_th[3]="24",defaultString_tmi[3]="00"; + /* End definitions for search routins */ + + switch (option) { + case ALARM_FILE: + operandFile = ALARM_FILE; + app_shell = alarm_shell; + break; + case OPMOD_FILE: + operandFile = OPMOD_FILE; + app_shell = opmod_shell; + break; + } + + if (app_shell && XtIsManaged(app_shell)) { + + viewFileUsedLength[option] = 0; + viewFileMaxLength[option] = 0; + + XtFree((char *)viewFileString[option]); + viewFileString[option]=NULL; + XtUnmanageChild(app_shell); + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + + return; + } + + XtVaSetValues(menuButton, XmNset, TRUE, NULL); + + strcpy(filename,FS_filename); +#ifndef WIN32 + directory = opendir(filename); + if (directory) { + closedir(directory); + sprintf(sbuf, "%s is a directory\n",filename); + createDialog(w,XmDIALOG_WARNING,sbuf," "); + return; + } +#endif + if ((fp = fopen(filename, "r")) == NULL) { + sprintf(sbuf, "fileViewWindow: Can't open file %s\n",filename); + createDialog(w,XmDIALOG_WARNING,sbuf," "); + fprintf(stderr, "Can't open file %s\n",filename); + return; + } + + if (stat(filename, &statbuf) == 0) + viewFileUsedLength[operandFile] = statbuf.st_size; + else + viewFileUsedLength[operandFile] = 1000000; /* arbitrary file length */ + + if (statbuf.st_size > 1000000) + { + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + createDialog(XtParent(w),XmDIALOG_ERROR,filename, &error_file_size[0]); + return; + } + + + /* read the file string */ + viewFileMaxLength[operandFile] = MAX(INITIAL_FILE_LENGTH, + 2*viewFileUsedLength[operandFile]); + if (alarmLogFileMaxRecords) + viewFileMaxLength[operandFile] = alarmLogFileStringLength*alarmLogFileMaxRecords; + + viewFileString[operandFile] = (unsigned char *) + XtCalloc(1,(unsigned)viewFileMaxLength[operandFile]); + + if(!viewFileString[operandFile]) { + XtVaSetValues(menuButton, XmNset, FALSE, NULL); + createDialog(XtParent(w),XmDIALOG_ERROR,"no free memory",""); + return; + } + + fread(viewFileString[operandFile], sizeof(char), + viewFileUsedLength[operandFile], fp); + + /* close up the file */ + fclose (fp) ; + + if (!app_shell) { + /* create view window dialog */ + ac = 0; + XtSetArg (al[ac], XmNy, 47); + ac++; + XtSetArg (al[ac], XmNx, 77); + ac++; + /* + XtSetArg (al[ac], XmNallowShellResize, FALSE); ac++; + */ + XtSetArg (al[ac], XmNallowOverlap, FALSE); + ac++; + XtSetArg(al[ac], XmNautoUnmanage, FALSE); + ac++; + switch (option) { + case CONFIG_FILE: + str = XmStringLtoRCreate("Configuration File", XmSTRING_DEFAULT_CHARSET); + break; + case ALARM_FILE: + str = XmStringLtoRCreate("Alarm Log File", XmSTRING_DEFAULT_CHARSET); + break; + case OPMOD_FILE: + str = XmStringLtoRCreate("Operator Mod File", XmSTRING_DEFAULT_CHARSET); + break; + } + XtSetArg(al[ac], XmNdialogTitle, str); + ac++; + app_shell = XmCreateFormDialog(XtParent(w), "SCROLL", al, ac); + XmStringFree(str); + XtVaSetValues(app_shell, XmNallowOverlap, FALSE, NULL); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(XtParent(app_shell), + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(XtParent(app_shell)), + "WM_DELETE_WINDOW", False); + operandFileLong = operandFile; + XmAddWMProtocolCallback(XtParent(app_shell),WM_DELETE_WINDOW, + (XtCallbackProc)closeFileViewShell, (XtPointer)operandFileLong); + } + switch (option) { + case ALARM_FILE: + alarm_shell = app_shell; + break; + case OPMOD_FILE: + opmod_shell = app_shell; + break; + } + + /* add close button */ + ac = 0; + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNtopOffset, 5); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNleftOffset, 5); + ac++; + XtSetArg (al[ac], XmNuserData, menuButton); + ac++; + button = XtCreateManagedWidget("Close",xmPushButtonWidgetClass, + app_shell, al, ac); + operandFileLong = operandFile; + XtAddCallback(button, XmNactivateCallback, + (XtCallbackProc)closeFileViewWindow_callback, + (XtPointer) operandFileLong); + + previous = button; + /* create file name widget */ + ac = 0; + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNtopOffset, 6); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_WIDGET); + ac++; + XtSetArg (al[ac], XmNleftWidget, button); + ac++; + XtSetArg (al[ac], XmNleftOffset, 6); + ac++; + viewFilenameWidget[operandFile] = XtCreateManagedWidget(filename,xmLabelGadgetClass, + app_shell,al, ac); + + /* For Search Widgets. + We define "Search" button in AlLogViewPanel. + */ + ac = 0; + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNtopOffset, 5); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_WIDGET); + ac++; + XtSetArg (al[ac], XmNleftWidget,viewFilenameWidget[operandFile] ); + ac++; + XtSetArg (al[ac], XmNleftOffset, 5); + ac++; + XtSetArg (al[ac], XmNuserData, menuButton); + ac++; + button1 = XtCreateManagedWidget("Search",xmPushButtonWidgetClass, + app_shell, al, ac); + XtAddCallback(button1, XmNactivateCallback, (XtCallbackProc)searchCallback, app_shell ); + ac = 0; + XtSetArg(al[ac], XmNallowShellResize, (XtArgVal) True); + ac++; + XtSetArg(al[ac], XmNmappedWhenManaged, (XtArgVal) False); + ac++; + findShell=XtVaCreatePopupShell("pshell",transientShellWidgetClass,app_shell, + NULL); + findPane = XtVaCreateManagedWidget("findPane", xmPanedWindowWidgetClass, + findShell,NULL); + ac = 0; + XtSetArg(al[ac], XmNhorizontalSpacing, (XtArgVal) 5); + ac++; + XtSetArg(al[ac], XmNverticalSpacing, (XtArgVal) 5); + ac++; + findBox = XtCreateManagedWidget("findBox", xmRowColumnWidgetClass, + findPane, al, ac); + ac = 0; + XtSetArg(al[ac], XmNleftAttachment, (XtArgVal) XmATTACH_FORM); + ac++; + XtSetArg(al[ac], XmNrightAttachment, (XtArgVal) XmATTACH_FORM); + ac++; + XtSetArg(al[ac], XmNtopAttachment, (XtArgVal) XmATTACH_FORM); + ac++; + str= XmStringCreateLtoR("Search:",XmFONTLIST_DEFAULT_TAG); + XtSetArg(al[ac], XmNlabelString, str); + ac++; + XtSetArg(al[ac], XmNalignment, (XtArgVal) XmALIGNMENT_CENTER); + ac++; + findLabel = XtCreateManagedWidget("findLabel", xmLabelWidgetClass, + findBox, al, ac); + XmStringFree(str); + ac = 0; + XtSetArg(al[ac], XmNleftAttachment, (XtArgVal) XmATTACH_FORM); + ac++; + XtSetArg(al[ac], XmNrightAttachment, (XtArgVal) XmATTACH_FORM); + ac++; + XtSetArg(al[ac], XmNtopAttachment, (XtArgVal) XmATTACH_WIDGET); + ac++; + XtSetArg(al[ac], XmNtopWidget, (XtArgVal) findLabel); + ac++; + XtSetArg(al[ac], XmNcolumns, (XtArgVal) 40); + ac++; + findText = XtCreateManagedWidget("findText", xmTextWidgetClass, findBox, + al, ac); + XtAddCallback(findText, XmNactivateCallback, (XtCallbackProc)findForward, NULL); + ac = 0; + XtSetArg(al[ac], XmNborderWidth, (XtArgVal) 0); + ac++; + XtSetArg(al[ac], XmNorientation, (XtArgVal) XmHORIZONTAL); + ac++; + findButtonBox=XtCreateManagedWidget("findButtonBox", xmRowColumnWidgetClass, + findPane, al, ac); + ac = 0; + str= XmStringCreateLtoR("Forward",XmFONTLIST_DEFAULT_TAG); + XtSetArg(al[ac], XmNlabelString,str); + ac++; + findForwardButton = XtCreateManagedWidget("findForwardButton", + xmPushButtonWidgetClass, findButtonBox, al, ac); + XtAddCallback(findForwardButton, XmNactivateCallback, (XtCallbackProc)findForward, + app_shell); + XmStringFree(str); + ac = 0; + str= XmStringCreateLtoR("Reverse",XmFONTLIST_DEFAULT_TAG); + XtSetArg(al[ac], XmNlabelString, str); + ac++; + findReverseButton = XtCreateManagedWidget("findReverseButton", + xmPushButtonWidgetClass, findButtonBox, al, ac); + XtAddCallback(findReverseButton,XmNactivateCallback,(XtCallbackProc)findReverse,app_shell); + XmStringFree(str); + ac = 0; + str= XmStringCreateLtoR("Dismiss",XmFONTLIST_DEFAULT_TAG); + XtSetArg(al[ac], XmNlabelString, str); + ac++; + findDismissButton = XtCreateManagedWidget("findDismissButton", + xmPushButtonWidgetClass, findButtonBox, al, ac); + XtAddCallback(findDismissButton, XmNactivateCallback, (XtCallbackProc)findDismiss, NULL); + XmStringFree(str); + ac = 0; + XtSetArg(al[ac], XmNmarginHeight, &margin_height); + ac++; + XtGetValues(findButtonBox, al, ac); + ac = 0; + XtSetArg(al[ac], XmNheight, &height); + ac++; + XtGetValues(findDismissButton, al, ac); + ac = 0; + XtSetArg(al[ac], XmNpaneMinimum, + (XtArgVal) (height + (margin_height * 2))); + ac++; + XtSetArg(al[ac], XmNpaneMaximum, + (XtArgVal) (height + (margin_height * 2))); + ac++; + XtSetValues(findButtonBox, al, ac); + XtRealizeWidget(findShell); + previous = button1; + + timeofday = time(0L); + tms = localtime(&timeofday); + sprintf(buf,"%04d%02d%02d", + 1900+tms->tm_year,1+tms->tm_mon,tms->tm_mday); + sscanf(buf,"%4s%2s%2s", + defaultString_fy,defaultString_fmo,defaultString_fd); + sscanf(buf,"%4s%2s%2s", + defaultString_ty,defaultString_tmo,defaultString_td); + + ac=0; + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_WIDGET); + ac++; + XtSetArg (al[ac], XmNtopWidget,button ); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNrightAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNorientation, XmHORIZONTAL); + ac++; + rowcol1= + XtCreateManagedWidget("rowcol1",xmRowColumnWidgetClass,app_shell, al,ac); + ac=0; + XtSetArg (al[ac], XmNcolumns, 4); + ac++; + XtSetArg (al[ac], XmNmaxLength, 4); + ac++; + XtVaCreateManagedWidget("From:(YYYY-MM-DD-HH-MI)",xmLabelGadgetClass, + rowcol1, NULL); + text_fy= + XtCreateManagedWidget("tex_fy",xmTextFieldWidgetClass, rowcol1,al,ac); + XtVaSetValues(text_fy, XmNvalue,defaultString_fy, NULL); + XtAddCallback(text_fy, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + XtSetArg (al[ac], XmNcolumns, 2); + ac++; + XtSetArg (al[ac], XmNmaxLength, 2); + ac++; + text_fmo= + XtCreateManagedWidget("tex_fmo",xmTextFieldWidgetClass,rowcol1,al,ac); + XtVaSetValues(text_fmo, XmNvalue,defaultString_fmo, NULL); + XtAddCallback(text_fmo, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + text_fd= + XtCreateManagedWidget("tex_fd",xmTextFieldWidgetClass, rowcol1,al,ac); + XtVaSetValues(text_fd, XmNvalue,defaultString_fd, NULL); + XtAddCallback(text_fd, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + text_fh= + XtCreateManagedWidget("tex_fh",xmTextFieldWidgetClass,rowcol1,al,ac); + XtVaSetValues(text_fh, XmNvalue,defaultString_fh, NULL); + XtAddCallback(text_fh, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + text_fmi= + XtCreateManagedWidget("tex_fmi",xmTextFieldWidgetClass,rowcol1,al,ac); + XtVaSetValues(text_fmi, XmNvalue,defaultString_fmi, NULL); + XtAddCallback(text_fmi, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + XtVaCreateManagedWidget("With:",xmLabelGadgetClass, rowcol1, NULL); + + text_with= + XtVaCreateManagedWidget("tex_with",xmTextFieldWidgetClass, rowcol1,NULL); + XtManageChild(rowcol1); + ac=0; + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_WIDGET); + ac++; + XtSetArg (al[ac], XmNtopWidget,rowcol1 ); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNrightAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNorientation, XmHORIZONTAL); + ac++; + rowcol2= + XtCreateManagedWidget("rowcol1",xmRowColumnWidgetClass,app_shell, al,ac); + ac=0; + XtSetArg (al[ac], XmNcolumns, 4); + ac++; + XtSetArg (al[ac], XmNmaxLength, 4); + ac++; + XtVaCreateManagedWidget(" To:(YYYY-MM-DD-HH-MI)",xmLabelGadgetClass, + rowcol2, NULL); + text_ty= + XtCreateManagedWidget("tex_ty",xmTextFieldWidgetClass, rowcol2,al,ac); + XtVaSetValues(text_ty, XmNvalue,defaultString_ty, NULL); + XtAddCallback(text_ty, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + XtSetArg (al[ac], XmNcolumns, 2); + ac++; + XtSetArg (al[ac], XmNmaxLength, 2); + ac++; + text_tmo= + XtCreateManagedWidget("tex_tmo",xmTextFieldWidgetClass,rowcol2,al,ac); + XtVaSetValues(text_tmo, XmNvalue,defaultString_tmo, NULL); + XtAddCallback(text_tmo, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + text_td= + XtCreateManagedWidget("tex_td",xmTextFieldWidgetClass,rowcol2,al,ac); + XtVaSetValues(text_td, XmNvalue,defaultString_td, NULL); + XtAddCallback(text_td, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + text_th= + XtCreateManagedWidget("tex_th",xmTextFieldWidgetClass,rowcol2,al,ac); + XtVaSetValues(text_th, XmNvalue,defaultString_th, NULL); + XtAddCallback(text_th, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + text_tmi= + XtCreateManagedWidget("tex_tmi",xmTextFieldWidgetClass,rowcol2,al,ac); + XtVaSetValues(text_tmi, XmNvalue,defaultString_tmi, NULL); + XtAddCallback(text_tmi, XmNmodifyVerifyCallback, (XtCallbackProc)allDigit, NULL); + + showButton=XtVaCreateManagedWidget("ShowSelected", + xmPushButtonWidgetClass,rowcol2, NULL); + XtAddCallback(showButton,XmNactivateCallback,showSelectedCallback,app_shell); + + long optionLong=option; + showAllButton=XtVaCreateManagedWidget("Show Current File", + xmPushButtonWidgetClass,rowcol2, NULL); + XtAddCallback(showAllButton, XmNactivateCallback,showAllCallback,(XtPointer)optionLong); + + XtManageChild(rowcol2); + previous = rowcol2; + /* End for Search Widgets. ______________________ */ + + + /* add titles */ + ac = 0; + XtSetArg (al[ac], XmNwidth,1200); + ac++; + XtSetArg (al[ac], XmNheight,30); + ac++; + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_WIDGET); + ac++; + XtSetArg (al[ac], XmNtopWidget, previous); + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM); + ac++; + switch (option) { + case ALARM_FILE: + if (!_description_field_flag) { + if (_global_flag) + title = XtCreateManagedWidget("TIME_STAMP PROCESS_VARIABLE_NAME CURRENT_STATUS UNACK_SEV ACKT VALUE", + xmLabelGadgetClass,app_shell,al,ac); + else title = XtCreateManagedWidget("TIME_STAMP PROCESS_VARIABLE_NAME CURRENT_STATUS VALUE", + xmLabelGadgetClass,app_shell,al,ac); + } else { /* _description_field_flag set */ + if (_global_flag) + title = XtCreateManagedWidget( +" TIME RECORD DESCRIPTION VALUE STATUS / SEVERITY / UNACK_SEV / ACKT", + xmLabelGadgetClass,app_shell,al,ac); + else title = XtCreateManagedWidget( +" TIME RECORD DESCRIPTION VALUE STATUS / SEVERITY", + xmLabelGadgetClass,app_shell,al,ac); + } + break; + case OPMOD_FILE: + title = XtCreateManagedWidget("TIME_STAMP LOG_MESSAGE", + xmLabelGadgetClass,app_shell,al,ac); + break; + } + previous = title; + + + + /* create text widget */ + ac = 0; + XtSetArg (al[ac], XmNrows, 30); + ac++; + XtSetArg (al[ac], XmNcolumns, 80); + ac++; + XtSetArg (al[ac], XmNscrollVertical, True); + ac++; + XtSetArg (al[ac], XmNscrollHorizontal, True); + ac++; + XtSetArg (al[ac], XmNeditMode, XmMULTI_LINE_EDIT); + ac++; + XtSetArg (al[ac], XmNeditable, FALSE); + ac++; + XtSetArg (al[ac], XmNcursorPositionVisible, FALSE); + ac++; + if (previous) { + XtSetArg (al[ac], XmNtopAttachment, XmATTACH_WIDGET); + ac++; + XtSetArg (al[ac], XmNtopWidget, previous); + } + ac++; + XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNrightAttachment, XmATTACH_FORM); + ac++; + XtSetArg (al[ac], XmNbottomAttachment, XmATTACH_FORM); + ac++; + browserWidget=XmCreateScrolledText(app_shell, "text", al, ac); + + /* make appropriate item sensitive */ + XtSetSensitive(browserWidget, True); + XmAddTabGroup(browserWidget); + + XtManageChild(browserWidget); + + } + /* update the file name string */ + str = XmStringLtoRCreate(filename, XmSTRING_DEFAULT_CHARSET); + XtVaSetValues(viewFilenameWidget[operandFile], XmNlabelString, str, NULL); + XmStringFree(str); + + /* add the file string to the text widget */ + XmTextSetString(browserWidget, (char *)viewFileString[operandFile]); + XtVaSetValues(browserWidget, + XmNcursorPosition, alarmLogFileOffsetBytes+1, + NULL); + XmTextShowPosition(browserWidget, alarmLogFileOffsetBytes+1); + + XtManageChild(app_shell); +} + +/************************************************************************** + Callback for ShowAll Button +**************************************************************************/ +static void showAllCallback(Widget w,XtPointer client_data,XtPointer call_data) +{ + int index = (long)client_data; + switch (index) { + case ALARM_FILE: + XmTextSetString(browserWidget, + (char *)viewFileString[ALARM_FILE]); + break; + case OPMOD_FILE: + XmTextSetString(browserWidget, + (char *)viewFileString[OPMOD_FILE]); + break; + } + + XtManageChild(browserWidget); +} + +/************************************************************************** + Callback for ShowSelected Button +**************************************************************************/ +static void showSelectedCallback(Widget w,XtPointer client_data, +XtPointer call_data) +{ + FILE *ffp; + char *fy,*fmo,*fd,*fh,*fmi,*ty,*tmo,*td,*th,*tmi; + char *string_with; + char month[10], day[10], hour[10], min[10], year[10], un1[10],un2[10]; + Boolean found; + char *p; +#ifndef WIN32 + DIR *directory; + struct dirent *rdr; +#endif + char fname[120]; + char FSnameshort[120]; + char buf1[13], buf2[13]; + static Cursor waitCursor; + XSetWindowAttributes attrs; + char lin[250]; + char *selectedText; + char *dirForAlLog; + int count=0; + register int gap, i, j; + char **v; + register char *temp; + char fromStr[11]; + char toStr[11]; + int len; + int begin=0; + int end=0; + int tmp=1; + Boolean breakFlag=False; + char *line=&lin[0]; + int bufferSize= MAX(viewFileMaxLength[ALARM_FILE],viewFileMaxLength[OPMOD_FILE]); + + fy =XmTextGetString(text_fy); + fmo=XmTextGetString(text_fmo); + fd =XmTextGetString(text_fd); + fh =XmTextGetString(text_fh); + fmi=XmTextGetString(text_fmi); + ty =XmTextGetString(text_ty); + tmo=XmTextGetString(text_tmo); + td =XmTextGetString(text_td); + th =XmTextGetString(text_th); + tmi=XmTextGetString(text_tmi); + + compactData(fy,fmo,fd,fh,fmi,&buf1[0]); + compactData(ty,tmo,td,th,tmi,&buf2[0]); + if(strcmp(buf1,buf2) > 0) + { + createDialog((Widget) client_data, XmDIALOG_WARNING, + "DataFrom > DataTo.\n","Please, change Data"); + XtFree(fy); + XtFree(fmo); + XtFree(fh); + XtFree(fd); + XtFree(fmi); + XtFree(ty); + XtFree(tmo); + XtFree(th); + XtFree(td); + XtFree(tmi); + return; + } + + dirForAlLog=XtCalloc(1,MAX_NUM_OF_LOG_FILES); + strcpy( FSnameshort, (const char *)shortfile(FS_filename) ); + strncpy(dirForAlLog,FS_filename,strlen(FS_filename)-strlen(FSnameshort)-1); +#ifndef WIN32 + if ( (directory=opendir( (char *) dirForAlLog)) == NULL) + { + fprintf(stderr,"%s-wrong directory\n",dirForAlLog); + XtFree(dirForAlLog); + XtFree(fy); + XtFree(fmo); + XtFree(fh); + XtFree(fd); + XtFree(fmi); + XtFree(ty); + XtFree(tmo); + XtFree(th); + XtFree(td); + XtFree(tmi); + return; + } +#endif + + string_with=XmTextGetString(text_with); + selectedText=XtCalloc(1,bufferSize); + if (!waitCursor) waitCursor=XCreateFontCursor(display,XC_watch); + attrs.cursor=waitCursor; + XChangeWindowAttributes(display,XtWindow((Widget)client_data),CWCursor,&attrs); + XFlush(display); + + len=strlen(FSnameshort)-10; /* length of name without "extension" */ +#ifndef WIN32 + while((rdr=readdir(directory))) + { + if( strncmp(rdr->d_name,FSnameshort,len )) continue; + if(!extensionIsDate(rdr->d_name+len)) continue; + count++; + } + closedir(directory); + if ( (directory=opendir( (char *) dirForAlLog)) == NULL) + { + fprintf(stderr,"%s-wrong directory\n",dirForAlLog); + XtFree(dirForAlLog); + XtFree(fy); + XtFree(fmo); + XtFree(fh); + XtFree(fd); + XtFree(fmi); + XtFree(ty); + XtFree(tmo); + XtFree(th); + XtFree(td); + XtFree(tmi); + return; + } +#endif + + v=(char **) calloc(sizeof(char *),count); + i=0; +#ifndef WIN32 + while((rdr=readdir(directory))) { + if( strncmp(rdr->d_name,FSnameshort,len )) continue; + if(!extensionIsDate(rdr->d_name+len)) continue; + v[i]=(char *)XtCalloc(sizeof(char), strlen(FSnameshort)+1 ); + strcpy(v[i],rdr->d_name); + v[i][strlen(FSnameshort)]=0; + i++; + } + closedir(directory); +#endif + + /* BinarySortAlgoritm from C&R */ + for (gap = count/2; gap > 0; gap /= 2) + for (i = gap; i < count; i++) + for (j=i-gap; j>=0 && (strcmp(v[j],v[j+gap])>0); j-=gap) { + temp = v[j]; + v[j] = v[j+gap]; + v[j+gap] = temp; + } + + memcpy(&fromStr[0],fy,4); + fromStr[4]='-'; + memcpy(&fromStr[5],fmo,2); + fromStr[7]='-'; + memcpy(&fromStr[8],fd,2); + fromStr[10]=0; + memcpy(&toStr[0],ty,4); + toStr[4]='-'; + memcpy(&toStr[5],tmo,2); + toStr[7]='-'; + memcpy(&toStr[8],td,2); + toStr[10]=0; + + for(i=0;i<count;i++) if((tmp=strcmp(v[i]+len,fromStr)) >=0 ) break; + begin=i; + if(tmp != 0) + { + fh[0]=fh[1]=fmi[0]=fmi[1]='0'; /* We must search from YYYY-MM-DD-00-00 */ + } /* in this case */ + + for(i=0;i<count;i++) if((tmp=strcmp(v[i]+len,toStr)) > 0 ) break; + end=i; + if(i==0) breakFlag=True; + else if( strcmp( v[i-1]+len,toStr) != 0) + { + th[0]='2'; th[1]='4'; tmi[0]=tmi[1]='0'; /*We must search to YYYY-MM-DD-24-00*/ + } /* in this case */ + + for( i=begin; (i<end)&&(!breakFlag) ;i++) + { + memset(&fname[0],0,120); + strcat(&fname[0],dirForAlLog); + strcat(fname,"/"); + strcat(fname,v[i]); + if( (ffp=fopen(fname,"r")) == NULL) { + createDialog((Widget) client_data, XmDIALOG_WARNING,fname, + " - can't open file!"); + continue; + } + XFlush(display); + XmUpdateDisplay(client_data); + + while ( fgets(line,250,ffp) ) { + if(isdigit(line[0])) /* new time format */ + sscanf(line,"%3s %4s %5s %3s %3s", + day, month,year,hour,min); + else { /* old time format */ + sscanf(line,"%4s %4s %3s %3s %3s %3s %4s", + un1,month,day,hour,min,un2,year); + month[3]=day[2]=hour[2]=min[2]=year[4]=0; + + if(atoi(day)<10) + { + day[1]=day[0]; /* It's leading ZERO problem, because in LogFile for day<10 */ + day[0]='0'; /* we have notation like " 3 Apr" not " 03 Apr" */ + } + } + + month[3]=day[2]=hour[2]=min[2]=year[4]=0; + + compactDataAscMonth(year,month,day,hour,min,&buf1[0]); + compactData(fy,fmo,fd,fh,fmi,&buf2[0]); + if( strcmp(&buf1[0],&buf2[0]) < 0 ) continue; + + compactData(ty,tmo,td,th,tmi,&buf2[0]); + if( strcmp(&buf1[0],&buf2[0]) > 0 ) continue; + if (strlen(string_with)){ + found=False; + for (p = line;(p = strchr( (const char *)p, *string_with)); p++){ + if (!strncmp(p,string_with,strlen(string_with))) {found=True;break;} + } + if (!found) continue; + } + + if( strlen(selectedText) >(size_t)(bufferSize - 2*250) ) + { + + createDialog((Widget) w, XmDIALOG_ERROR, + "Result of the search is so long.\nPlease, detail search context.\n", + "I show only beginning of result."); + + breakFlag=True; + break; /* Break from while( fgets()) */ + } + strcat(selectedText,line); + } + fclose(ffp); + } + + for(i=0;i<count;i++) XtFree(v[i]); + free(v); + XtFree(dirForAlLog); + XtFree(string_with); + XtFree(fy); + XtFree(fmo); + XtFree(fh); + XtFree(fd); + XtFree(fmi); + XtFree(ty); + XtFree(tmo); + XtFree(th); + XtFree(td); + XtFree(tmi); + + XmTextSetString(browserWidget,selectedText); + attrs.cursor=None; + XChangeWindowAttributes(display,XtWindow ((Widget)client_data),CWCursor,&attrs); + XFlush(display); + + + XtManageChild(browserWidget); + XtFree(selectedText); +} + + + + +/************************************************************************** + allDigit +**************************************************************************/ +static void allDigit(Widget text_w,XtPointer unused,XmTextVerifyCallbackStruct *cbs) +{ + char c; + int len = XmTextGetLastPosition(text_w); + if (cbs->text->ptr == NULL) return; /* backspace */ + /* don't allow non-digits or let the input exceed 5 chars */ + if (!isdigit(c = cbs->text->ptr[0]) || len >= 5) + cbs->doit = False; +} + +/****************************************************************** + searchCallback callback routine for Search widgets. +*****************************************************************/ +static void searchCallback(Widget w,XtPointer client_data, +XmAnyCallbackStruct *call_data) +{ + if (XtIsRealized(findShell)) XtMapWidget(findShell); + XtPopup(findShell, XtGrabNone); + /* XMapRaised(XtDisplay(findShell), XtWindow(XtParent(findShell))); */ +} + +/****************************************************************** + findForward callback routine for Search widgets. +*****************************************************************/ +static void findForward(Widget w,XtPointer client_data, +XtPointer call_data) +{ + char *search_pat, *p, *string; + Boolean found = False; + Widget text_w,search_w; + text_w = browserWidget; + search_w=findText; + string = XmTextGetString(text_w); + if (!*string) { + createDialog((Widget)findShell,XmDIALOG_WARNING,"No text to search."," "); + XtFree(string); + return; + } + search_pat = XmTextGetString(search_w); + if (!*search_pat) { + createDialog((Widget)client_data,XmDIALOG_WARNING, + "Specify a search pattern."," "); + XtFree(string); + XtFree(search_pat); + return; + } + XmTextSetHighlight(text_w,positionSearch,positionSearch+lenSearch, + XmHIGHLIGHT_NORMAL); + lenSearch=strlen(search_pat); + positionSearch = XmTextGetCursorPosition(text_w); + for(p=&string[positionSearch+1];(p=strchr((const char *)p,*search_pat));p++) + if (!strncmp(p, search_pat, lenSearch)) { + found = True; + break; + } + if (!found) { + createDialog((Widget)client_data,XmDIALOG_WARNING, + "Forward Pattern not found."," "); + } + else { + positionSearch = (XmTextPosition)(p - string); + XmTextSetInsertionPosition(text_w, positionSearch); + XmTextSetHighlight(text_w,positionSearch,positionSearch+lenSearch, + XmHIGHLIGHT_SELECTED); + } + XtFree(string); + XtFree(search_pat); +} + +/****************************************************************** + findReverse callback routine for Search widgets. +*****************************************************************/ +static void findReverse(Widget w,XtPointer client_data, +XtPointer call_data) +{ + char *search_pat, *p=0, *string; + Boolean found = False; + Widget text_w,search_w; + text_w = browserWidget; + search_w=findText; + string = XmTextGetString(text_w); + if (!*string) { + createDialog((Widget)client_data,XmDIALOG_WARNING,"No text to search."," "); + XtFree(string); + return; + } + search_pat = XmTextGetString(search_w); + if (!*search_pat) { + createDialog((Widget)client_data,XmDIALOG_WARNING, + "Specify a search pattern."," "); + XtFree(string); + XtFree(search_pat); + return; + } + XmTextSetHighlight(text_w,positionSearch,positionSearch+lenSearch, + XmHIGHLIGHT_NORMAL); + lenSearch=strlen(search_pat); + if((positionSearch=XmTextGetCursorPosition(text_w))>0) + { + for (p = &string[positionSearch-1]; p >= string; p--) + if (!strncmp(p, search_pat, lenSearch)) { + found = True; + break; + } + } + if (!found) { + createDialog((Widget)client_data,XmDIALOG_WARNING, + "Reverse pattern not found."," "); + } + else { + positionSearch = (XmTextPosition)(p - string); + XmTextSetInsertionPosition(text_w, positionSearch); + XmTextSetHighlight(text_w,positionSearch,positionSearch+lenSearch, + XmHIGHLIGHT_SELECTED); + } + XtFree(string); + XtFree(search_pat); +} + +/****************************************************************** + findDismiss callback routine for Search widgets. +*****************************************************************/ +static void findDismiss(Widget w,XtPointer client_data, +XtPointer call_data) +{ + XtUnmapWidget(findShell); +} + +/****************************************************************** + Compact presentation of YYY-MM-DD. +*****************************************************************/ +static void compactData(char *year,char *month,char *day,char *hour, +char *min,char *presentation) +{ + memcpy(&presentation[0],year,4); + memcpy(&presentation[4],month,2); + memcpy(&presentation[6],day,2); + memcpy(&presentation[8],hour,2); + memcpy(&presentation[10],min,2); + presentation[12]=0; +} + +/****************************************************************** + Compact presentation of YYY-MMM-DD. +*****************************************************************/ +static void compactDataAscMonth(char *year,char *month,char *day,char *hour, +char *min,char *presentation) +{ + compactData(year,digitalMonth(month),day,hour,min,presentation); +} + +/****************************************************************** + Month to Digit. +*****************************************************************/ +static char *digitalMonth(char *strMonth) +{ + if(!strcmp(strMonth,"Jan")) return("01"); + if(!strcmp(strMonth,"Feb")) return("02"); + if(!strcmp(strMonth,"Mar")) return("03"); + if(!strcmp(strMonth,"Apr")) return("04"); + if(!strcmp(strMonth,"May")) return("05"); + if(!strcmp(strMonth,"Jun")) return("06"); + if(!strcmp(strMonth,"Jul")) return("07"); + if(!strcmp(strMonth,"Aug")) return("08"); + if(!strcmp(strMonth,"Sep")) return("09"); + if(!strcmp(strMonth,"Oct")) return("10"); + if(!strcmp(strMonth,"Nov")) return("11"); + if(!strcmp(strMonth,"Dec")) return("12"); + fprintf(stderr,"%s --- NOT A MONTH !!!!!\n",strMonth); + return("00"); +} + +/****************************************************************** + Cheking that extension looks like YYYY-MM-DD. +*****************************************************************/ +static Boolean extensionIsDate(char *ext) +{ + if(*(ext+10) != 0) return False; + if(!isdigit(*ext)) return False; + if(!isdigit(*(ext+1))) return False; + if(!isdigit(*(ext+2))) return False; + if(!isdigit(*(ext+3))) return False; + if(*(ext+4) != '-') return False; + if(!isdigit(*(ext+5))) return False; + if(!isdigit(*(ext+6))) return False; + if(*(ext+7) != '-') return False; + if(!isdigit(*(ext+8))) return False; + if(!isdigit(*(ext+9))) return False; +return True; +} + + diff --git a/showmask.c b/showmask.c new file mode 100644 index 0000000..23e6659 --- /dev/null +++ b/showmask.c @@ -0,0 +1,646 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* showmask.c */ + +/************************DESCRIPTION*********************************** + showmask.c: a popup dialog window + This file contains routines for creating force mask dialog. +**********************************************************************/ + +#include <stdlib.h> + +#include <Xm/Xm.h> +#include <Xm/Form.h> +#include <Xm/Frame.h> +#include <Xm/LabelG.h> +#include <Xm/ToggleB.h> +#include <Xm/PanedW.h> +#include <Xm/Protocols.h> +#include <Xm/RowColumn.h> +#include <Xm/ToggleBG.h> + +#include "axArea.h" +#include "alLib.h" +#include "alh.h" +#include "ax.h" + +extern int _passive_flag; + +struct forceMaskWindow { + void *area; + Widget menuButton; + Widget maskDialog; + Widget nameLabelW; + Widget nameTextW; + Widget currentMaskLabel; + Widget currentMaskStringLabelW; + Widget resetMaskStringLabelW; + Widget alarmMaskStringLabelW; + Widget alarmMaskToggleButtonW[ALARM_NMASK]; + Widget maskFrameW; +}; + +/* forward declarations */ +static void forceMaskApplyCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void forceMaskResetCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void forceMaskDismissCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void forceMaskHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs); +static void forceMaskCreateDialog(ALINK*area); +static void forceMaskUpdateDialogWidgets(struct forceMaskWindow *forceMaskWindow); +static void forceMaskChangeCallback( Widget widget,XtPointer calldata,XtPointer cbs); + +/****************************************************** + forceMaskUpdateDialog +******************************************************/ +void forceMaskUpdateDialog(area) +ALINK *area; +{ + struct forceMaskWindow *forceMaskWindow; + + if (!area->forceMaskWindow) return; + + forceMaskWindow = (struct forceMaskWindow *)area->forceMaskWindow; + + if (!forceMaskWindow->maskDialog || !XtIsManaged(forceMaskWindow->maskDialog)) return; + + forceMaskUpdateDialogWidgets(forceMaskWindow); +} + +/****************************************************** + forceMaskShowDialog +******************************************************/ +void forceMaskShowDialog(area, menuButton) +ALINK *area; +Widget menuButton; +{ + struct forceMaskWindow *forceMaskWindow; + + forceMaskWindow = (struct forceMaskWindow *)area->forceMaskWindow; + + /* dismiss Dialog */ + if (forceMaskWindow && forceMaskWindow->maskDialog && + XtIsManaged(forceMaskWindow->maskDialog)) { + forceMaskDismissCallback(NULL, (XtPointer)forceMaskWindow, NULL); + return; + } + + /* create forceMaskWindow and Dialog Widgets if necessary */ + if (!forceMaskWindow) forceMaskCreateDialog(area); + + /* update forceMaskWindow */ + forceMaskWindow = (struct forceMaskWindow *)area->forceMaskWindow; + forceMaskWindow->menuButton = menuButton; + + /* update Dialog Widgets */ + forceMaskUpdateDialogWidgets(forceMaskWindow); + + /* show Dialog */ + if (!forceMaskWindow->maskDialog) return; + if (!XtIsManaged(forceMaskWindow->maskDialog)) { + XtManageChild(forceMaskWindow->maskDialog); + } + XMapWindow(XtDisplay(forceMaskWindow->maskDialog), + XtWindow(XtParent(forceMaskWindow->maskDialog))); + if (menuButton) XtVaSetValues(menuButton, XmNset, TRUE, NULL); + +} + +/****************************************************** + forceMaskUpdateDialogWidgets +******************************************************/ + +static void forceMaskUpdateDialogWidgets(forceMaskWindow) +struct forceMaskWindow *forceMaskWindow; +{ + struct gcData *pgcData; + GCLINK *link; + int linkType; + XmString string; + char buff[6]; + + if (! forceMaskWindow || !forceMaskWindow->maskDialog ) return; + + link = (GCLINK *)getSelectionLinkArea(forceMaskWindow->area); + + if (!link) { + + string = XmStringCreateSimple(""); + XtVaSetValues(forceMaskWindow->nameTextW,XmNlabelString, string, NULL); + XmStringFree(string); + string = XmStringCreateSimple("-----"); + XtVaSetValues(forceMaskWindow->currentMaskStringLabelW, XmNlabelString, string, NULL); + XtVaSetValues(forceMaskWindow->resetMaskStringLabelW, XmNlabelString, string, NULL); + XtVaSetValues(forceMaskWindow->alarmMaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[0],FALSE,TRUE); + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[1],FALSE,TRUE); + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[2],FALSE,TRUE); + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[3],FALSE,TRUE); + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[4],FALSE,TRUE); + return; + } + + linkType = getSelectionLinkTypeArea(forceMaskWindow->area); + + pgcData = link->pgcData; + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + if (linkType == GROUP) string = XmStringCreateSimple("Group Name:"); + else string = XmStringCreateSimple("Channel Name:"); + XtVaSetValues(forceMaskWindow->nameLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + + if (pgcData->alias){ + string = XmStringCreateSimple(pgcData->alias); + } else { + string = XmStringCreateSimple(pgcData->name); + } + XtVaSetValues(forceMaskWindow->nameTextW, XmNlabelString, string, NULL); + XmStringFree(string); + + /* --------------------------------- + Current Mask + --------------------------------- */ + if (linkType == GROUP) string = XmStringCreateSimple("Current Mask Summary:"); + else string = XmStringCreateSimple("Current Mask:"); + XtVaSetValues(forceMaskWindow->currentMaskLabel, XmNlabelString, string, NULL); + XmStringFree(string); + + if (linkType == GROUP) awGetMaskString(((struct groupData *)pgcData)->mask,buff); + else alGetMaskString(((struct chanData *)pgcData)->curMask,buff); + string = XmStringCreateSimple(buff); + XtVaSetValues(forceMaskWindow->currentMaskStringLabelW, XmNlabelString, string, NULL); + + /* + XtVaSetValues(forceMaskWindow->alarmMaskStringLabelW, XmNlabelString, string, NULL); + alSetMask(buff,&mask); + if (mask.Cancel == 1 ) + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[0],TRUE,TRUE); + else XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[0],FALSE,TRUE); + if (mask.Disable == 1 ) + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[1],TRUE,TRUE); + else XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[1],FALSE,TRUE); + if (mask.Ack == 1 ) + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[2],TRUE,TRUE); + else XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[2],FALSE,TRUE); + if (mask.AckT == 1 ) + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[3],TRUE,TRUE); + else XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[3],FALSE,TRUE); + if (mask.Log == 1 ) + XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[4],TRUE,TRUE); + else XmToggleButtonSetState(forceMaskWindow->alarmMaskToggleButtonW[4],FALSE,TRUE); + */ + + XmStringFree(string); + + /* --------------------------------- + Reset Mask + --------------------------------- */ + if (linkType == GROUP) string = XmStringCreateSimple(" "); + else { + alGetMaskString(((struct chanData *)pgcData)->defaultMask,buff); + string = XmStringCreateSimple(buff); + } + XtVaSetValues(forceMaskWindow->resetMaskStringLabelW, XmNlabelString, string, NULL); + XmStringFree(string); + +} + +/****************************************************** + forceMaskCreateDialog +******************************************************/ +static void forceMaskCreateDialog(area) +ALINK *area; +{ + struct forceMaskWindow *forceMaskWindow; + + Widget maskDialogShell, maskDialog; + Widget rowcol, form, maskFrameW; + Widget nameLabelW, nameTextW; + Widget alarmMaskToggleButtonW[ALARM_NMASK]; + Widget alarmMaskLabel, alarmMaskStringLabelW; + Widget currentMaskLabel, currentMaskStringLabelW; + Widget resetMaskLabel, resetMaskStringLabelW; + int i; + XmString string; + static ActionAreaItem mask_items[] = { + { "Apply", forceMaskApplyCallback, NULL }, + { "Reset", forceMaskResetCallback, NULL }, + { "Dismiss", forceMaskDismissCallback, NULL }, + { "Help", forceMaskHelpCallback, NULL }, + }; + static String maskFields[] = { + "Cancel Alarm", + "Disable Alarm", + "NoAck Alarm", + "NoAck Transient Alarm", + "NoLog Alarm" + }; + + if (!area) return; + + forceMaskWindow = (struct forceMaskWindow *)area->forceMaskWindow; + + if (forceMaskWindow && forceMaskWindow->maskDialog){ + if (XtIsManaged(forceMaskWindow->maskDialog)) return; + else XtManageChild(forceMaskWindow->maskDialog); + } + + + forceMaskWindow = (struct forceMaskWindow *)calloc(1,sizeof(struct forceMaskWindow)); + area->forceMaskWindow = (void *)forceMaskWindow; + forceMaskWindow->area = (void *)area; + + maskDialogShell = XtVaCreatePopupShell("Force Mask", + transientShellWidgetClass, area->toplevel, + XmNallowShellResize, TRUE, + NULL); + + /* Modify the window manager menu "close" callback */ + { + Atom WM_DELETE_WINDOW; + XtVaSetValues(maskDialogShell, + XmNdeleteResponse, XmDO_NOTHING, NULL); + WM_DELETE_WINDOW = XmInternAtom(XtDisplay(maskDialogShell), + "WM_DELETE_WINDOW", False); + XmAddWMProtocolCallback(maskDialogShell,WM_DELETE_WINDOW, + (XtCallbackProc)forceMaskDismissCallback, (XtPointer)forceMaskWindow); + } + + maskDialog = XtVaCreateWidget("maskDialog", + xmPanedWindowWidgetClass, maskDialogShell, + XmNallowResize, TRUE, + XmNsashWidth, 1, + XmNsashHeight, 1, + XmNuserData, area, + NULL); + + form = XtVaCreateWidget("control_area", + xmFormWidgetClass, maskDialog, + XmNallowResize, TRUE, + NULL); + + /* --------------------------------- + Group/Channel Name + --------------------------------- */ + nameLabelW = XtVaCreateManagedWidget("nameLabelW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_END, + XmNtopAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + XmNrecomputeSize, True, + (XtPointer)NULL); + + nameTextW = XtVaCreateManagedWidget("nameTextW", + xmLabelGadgetClass, form, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, nameLabelW, + XmNrightAttachment, XmATTACH_NONE, + XmNrecomputeSize, True, + NULL); + + /* --------------------------------- + Alarm Mask + --------------------------------- */ + string = XmStringCreateSimple("Current Mask:"); + currentMaskLabel = XtVaCreateManagedWidget("currentMaskLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNalignment, XmALIGNMENT_END, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, nameTextW, + XmNtopOffset, 5, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple("-----"); + currentMaskStringLabelW = XtVaCreateManagedWidget("currentMaskStringLabelW", + xmLabelGadgetClass, form, + XmNlabelString, string, + /*XmNbackground, 0,*/ + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, nameTextW, + XmNtopOffset, 5, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, currentMaskLabel, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple("Reset Mask:"); + resetMaskLabel = XtVaCreateManagedWidget("resetMaskLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNalignment, XmALIGNMENT_END, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, currentMaskLabel, + XmNtopOffset, 5, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple("-----"); + resetMaskStringLabelW = XtVaCreateManagedWidget("resetMaskStringLabelW", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, currentMaskStringLabelW, + XmNtopOffset, 5, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, resetMaskLabel, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple("Mask:"); + alarmMaskLabel = XtVaCreateManagedWidget("alarmMaskLabel", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNalignment, XmALIGNMENT_END, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, resetMaskLabel, + XmNtopOffset, 5, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + NULL); + XmStringFree(string); + + string = XmStringCreateSimple("-----"); + alarmMaskStringLabelW = XtVaCreateManagedWidget("alarmMaskStringLabelW", + xmLabelGadgetClass, form, + XmNlabelString, string, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, resetMaskStringLabelW, + XmNtopOffset, 5, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, alarmMaskLabel, + NULL); + XmStringFree(string); + + maskFrameW = XtVaCreateManagedWidget("maskFrameW", + xmFrameWidgetClass, form, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, alarmMaskStringLabelW, + XmNtopOffset, 5, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 25, + NULL); + + rowcol = XtVaCreateWidget("rowcol", + xmRowColumnWidgetClass, maskFrameW, + XmNspacing, 0, + XmNmarginHeight, 0, + NULL); + + for (i = 0; i < ALARM_NMASK; i++){ + alarmMaskToggleButtonW[i] = XtVaCreateManagedWidget(maskFields[i], + xmToggleButtonGadgetClass, rowcol, + XmNmarginHeight, 0, + XmNuserData, (XtPointer)alarmMaskStringLabelW, + NULL); + if (_passive_flag && i == ALARMACKT ) { + XtVaSetValues(alarmMaskToggleButtonW[i], XmNsensitive, FALSE, NULL); + } + long ilong=i; + XtAddCallback(alarmMaskToggleButtonW[i], XmNvalueChangedCallback, + (XtCallbackProc)forceMaskChangeCallback, (XtPointer)ilong); + } + + XtManageChild(rowcol); + + XtManageChild(form); + + /* Set the client data "Apply", "Reset", "Dismiss", and "Help" button's callbacks. */ + mask_items[0].data = (XtPointer)forceMaskWindow; + mask_items[1].data = (XtPointer)forceMaskWindow; + mask_items[2].data = (XtPointer)forceMaskWindow; + mask_items[3].data = (XtPointer)forceMaskWindow; + + (void)createActionButtons(maskDialog, mask_items, XtNumber(mask_items)); + + XtManageChild(maskDialog); + + forceMaskWindow->maskDialog = maskDialog; + forceMaskWindow->nameLabelW = nameLabelW; + forceMaskWindow->nameTextW = nameTextW; + forceMaskWindow->currentMaskLabel = currentMaskLabel; + forceMaskWindow->currentMaskStringLabelW = currentMaskStringLabelW; + forceMaskWindow->resetMaskStringLabelW = resetMaskStringLabelW; + forceMaskWindow->alarmMaskStringLabelW = alarmMaskStringLabelW; + forceMaskWindow->maskFrameW = maskFrameW; + for (i = 0; i < ALARM_NMASK; i++){ + forceMaskWindow->alarmMaskToggleButtonW[i] = alarmMaskToggleButtonW[i]; + } + + XtRealizeWidget(maskDialogShell); + +} + +/****************************************************** + forceMaskChangeCallback +******************************************************/ +static void forceMaskChangeCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + int index=(long)calldata; + char *mask; + Widget maskWidget; + XmString string; + + XtVaGetValues(widget, XmNuserData, &maskWidget, NULL); + + XtVaGetValues(maskWidget, XmNlabelString, &string, NULL); + XmStringGetLtoR(string, XmFONTLIST_DEFAULT_TAG, &mask); + XmStringFree(string); + + if (!XmToggleButtonGadgetGetState(widget)) { + mask[index] = '-'; + } + else { + switch (index) { + case ALARMCANCEL: + mask[index] = 'C'; + break; + case ALARMDISABLE: + mask[index] = 'D'; + break; + case ALARMACK: + mask[index] = 'A'; + break; + case ALARMACKT: + mask[index] = 'T'; + break; + case ALARMLOG: + mask[index] = 'L'; + break; + } + } + + string = XmStringCreateSimple(mask); + XtVaSetValues(maskWidget, XmNlabelString, string, NULL); + XmStringFree(string); + XtFree(mask); +} + +/****************************************************** + forceMaskHelpCallback +******************************************************/ +static void forceMaskHelpCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + char *message1 = + "Set the current mask for a group or channel.\n" + "Setting the mask for a group means setting the mask for all channels in the group.\n\n" + "Changing NoAck Transient Alarm is not allowed when executing in passive state.\n \n" + "Press the Apply button to force the mask on the selected channel or on\n" + " all channels in the selected group.\n" + ; + char *message2 = + "Press the Reset button to reset channel mask(s) to their initial values.\n" + "Press the Dismiss button to close the Force Mask dialog window.\n" + "Press the Help button to get this help description window.\n"; + ; + + createDialog(widget,XmDIALOG_INFORMATION, message1,message2); + +} + +/****************************************************** + forceMaskApplyCallback +******************************************************/ +static void forceMaskApplyCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + struct forceMaskWindow *forceMaskWindow=(struct forceMaskWindow *)calldata; + struct chanData *cdata; + XmString string; + char *buff; + struct gcData *pgcData; + GCLINK *link; + int linkType; + MASK mask; + + link =getSelectionLinkArea(forceMaskWindow->area); + if (!link) return; + pgcData = link->pgcData; + linkType =getSelectionLinkTypeArea(forceMaskWindow->area); + + /* --------------------------------- + Update alarm Mask + --------------------------------- */ + XtVaGetValues(forceMaskWindow->alarmMaskStringLabelW, XmNlabelString, &string, NULL); + XmStringGetLtoR(string,XmFONTLIST_DEFAULT_TAG,&buff); + XmStringFree(string); + alSetMask(buff,&mask); + if (linkType == CHANNEL) { + alRemoveNoAck1HrTimerChan((CLINK *)link); + alChangeChanMask((CLINK *)link,mask); + alCaFlushIo(); + + alLogOpModMessage(CHANGE_MASK,(GCLINK*)link, + "OPER Channel Set Mask <%s> [%s]", + link->pgcData->name, + buff); + + cdata = (struct chanData *)pgcData; + if (programId != ALH) cdata->defaultMask = cdata->curMask; + } + if (linkType == GROUP) { + alRemoveNoAck1HrTimerGroup((GLINK *)link); + alChangeGroupMask((GLINK *)link,mask); + alCaFlushIo(); + + alLogOpModMessage(CHANGE_MASK_GROUP,link, + "OPER Group Set Mask <%s> [%s]", + link->pgcData->name, + buff); + } + XtFree(buff); + + silenceCurrentReset(forceMaskWindow->area); + link->pmainGroup->modified = 1; + + /* --------------------------------- + Update all dialog Windows + --------------------------------- */ + axUpdateDialogs(forceMaskWindow->area); +} + +/****************************************************** + forceMaskResetCallback +******************************************************/ +static void forceMaskResetCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + struct forceMaskWindow *forceMaskWindow=(struct forceMaskWindow *)calldata; + struct chanData *cdata; + GCLINK *link; + int linkType; + char buff1[6]; + + link =getSelectionLinkArea(forceMaskWindow->area); + if (!link) return; + linkType =getSelectionLinkTypeArea(forceMaskWindow->area); + + if (linkType == CHANNEL) { + cdata = (struct chanData *)link->pgcData; + alRemoveNoAck1HrTimerChan((CLINK *)link); + alChangeChanMask((CLINK *)link,cdata->defaultMask); + alCaFlushIo(); + + alGetMaskString(cdata->curMask,buff1); + alLogOpModMessage(CHANGE_MASK,(GCLINK*)link, + "OPER Channel Reset Mask <%s> [%s]", + cdata->name, + buff1); + + if (programId != ALH) cdata->defaultMask = cdata->curMask; + } + if (linkType == GROUP) { + alRemoveNoAck1HrTimerGroup((GLINK *)link); + alResetGroupMask((GLINK *)link); + alCaFlushIo(); + + alLogOpModMessage(CHANGE_MASK_GROUP,link, + "OPER Group Reset Masks <%s>", + link->pgcData->name); + } + + silenceCurrentReset(forceMaskWindow->area); + link->pmainGroup->modified = 1; + + /* --------------------------------- + Update all dialog Windows + --------------------------------- */ + axUpdateDialogs(forceMaskWindow->area); + +} + +/****************************************************** + forceMaskDismissCallback +******************************************************/ +static void forceMaskDismissCallback(Widget widget,XtPointer calldata,XtPointer cbs) +{ + struct forceMaskWindow *forceMaskWindow=(struct forceMaskWindow *)calldata; + Widget maskDialog; + + maskDialog = forceMaskWindow->maskDialog; + XtUnmanageChild(maskDialog); + XUnmapWindow(XtDisplay(maskDialog), XtWindow(XtParent(maskDialog))); + if (forceMaskWindow->menuButton) + XtVaSetValues(forceMaskWindow->menuButton, XmNset, FALSE, NULL); +} + diff --git a/sllLib.c b/sllLib.c new file mode 100644 index 0000000..d03e655 --- /dev/null +++ b/sllLib.c @@ -0,0 +1,164 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* sllLib.c */ + +/************************DESCRIPTION*********************************** + *PUBLIC* functions for single link list operations. +**********************************************************************/ + +#include <stdio.h> +#include "sllLib.h" + +/********************************************************* + add a node at the end of the list +**********************************************************/ +int sllAdd(SLIST *list,SNODE *new) +{ + if (list->count > 0) { + list->last->next = new; + + } + else + list->first = new; + new->next = NULL; + list->last = new; + list->count++; + return(0); +} + +/********************************************************* + find the N th node of the list +**********************************************************/ +SNODE *sllNth(SLIST *list,int n) +{ + SNODE *pt; + int i,count; + + count = list->count; + if (n >= count) return(list->last); + if ( n <= 0) return(list->first); + pt = list->first; + for (i=1;i<n;i++) + pt = pt->next; + return(pt); +} + +/********************************************************* + insert a node after prev node of the list +**********************************************************/ +void sllInsert(SLIST *list,SNODE *prev,SNODE *new) +{ + if (prev == NULL) { + new->next = list->first; + list->first = new; + } + else if (prev == list->last) { + prev->next = new; + list->last = new; + new->next = NULL; + } + else { + new->next = prev->next; + prev->next = new; + } + list->count++; + return; + +} + +/********************************************************* + insert a new node before next node of the list +**********************************************************/ +int sllPrecede(SLIST *list,SNODE *next,SNODE *new) +{ + SNODE *prev,*last,*now; + + if (next == NULL) { + if (list->count == 0){ + list->first = new; + list->last = new; + } + else { + last = list->last; + last->next = new; + list->last = new; + } + } + else { + prev = NULL; + now = list->first; + + while (now ) { + if (now == next) break; + prev = now; + now = now->next; + } + if (now) { + new->next = now; + if (prev == NULL) + list->first = new; + else prev->next = new; + } + else return(-1); + } + list->count++; + return(0); +} + +/********************************************************* + remove the node from the list +**********************************************************/ +void sllRemove(SLIST *list,SNODE *node) +{ + SNODE *prev,*now,*last; + prev = NULL; + now = list->first; + last = list->last; + + while (now ) { + if (now == node) break; + else { + prev = now; + now = now->next; + } + } + if (now) { + if (prev == NULL){ + list->first = now->next; + prev = node; + } + else prev->next = now->next; + if (node == last) list->last = prev; + list->count--; + } +} + +/********************************************************* + find the node from the list +**********************************************************/ +int sllFind(SLIST *plist,SNODE *pnode) +{ + int i; + SNODE *pt; + pt = plist->first; + for (i=1;i<=plist->count;i++) { + if (pt == pnode) { + return(i); + } + pt = sllNext(pt); + } + return(-1); +} + diff --git a/sllLib.h b/sllLib.h new file mode 100644 index 0000000..7fb4e70 --- /dev/null +++ b/sllLib.h @@ -0,0 +1,78 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* sllLib.h */ + +/************************DESCRIPTION*********************************** + *PUBLIC* functions for single link list operations. +**********************************************************************/ + +#ifndef INCsllLibh +#define INCsllLibh 1 + +struct snode { + struct snode *next; +}; +typedef struct snode SNODE; + +struct list { + SNODE *first; + SNODE *last; + int count; +}; +typedef struct list SLIST; + +#define sllFirst(PSLIST) \ + ((SNODE *)(((SLIST *)(PSLIST))->first)) + +#define sllInit(PSLIST) \ + (((SLIST *)(PSLIST))->first = NULL,\ + ((SLIST *)(PSLIST))->last = NULL,\ + ((SLIST *)(PSLIST))->count = 0) + +#define sllLast(PSLIST) \ + ((SNODE *)(((SLIST *)(PSLIST))->last)) + +#define sllNext(PSNODE) \ + (((PSNODE) == NULL) ? NULL : (((SNODE *)(PSNODE))->next)) + +/******************************************************************** + sllLib.c function prototypes +*********************************************************************/ +int sllAdd ( SLIST * plist, SNODE *pnode); +SNODE *sllNth ( SLIST*plist, int n); +void sllInsert( SLIST *plist, SNODE *pprev,SNODE *pnew); +int sllPrecede( SLIST *plist, SNODE *pnext,SNODE *pnew); +void sllRemove( SLIST *plist, SNODE *pnode); +int sllFind( SLIST *plist, SNODE *pnode); + +/*------------------------------------------------------------------------------------ +Routines defined in sllLib.c: + +sllAdd(plist,new) Add the new node to the plist +SNODE *sllNth(plist,n) Get the Nth node of the plist +int sllInsert(plist,prev,new) Insert the new node after the prev node +int sllRemove(plist,node) Remove the node from the plist +int sllFind(plist,pnode) Find the pnode from the plist + + +Macros defined in sllLib.h + +SNODE *sllFirst(plist) Return the first node of the plist +sllInit(plist) Initialize plist structure +SNODE *sllLast(plist) Return the last node of the plist +SNODE *sllNext(pnode) Return the next node pointer + +----------------------------------------------------------------------------------------*/ +#endif diff --git a/socket_sr_ora.pl b/socket_sr_ora.pl new file mode 100755 index 0000000..ed1c88e --- /dev/null +++ b/socket_sr_ora.pl @@ -0,0 +1,42 @@ +#!/usr/local/bin/perl +use Socket; +use Oraperl; +$lda = &ora_login('DESY','KHVOROST','ANATOLY') + || die $ora_errst; + +$fmt = "'DD-MON-YYYY HH24:MI:SS'"; +$csr_insert = &ora_open($lda,"insert into alarm (alarm_date,record_name,alarm_type_1,alarm_1,alarm_type_2,alarm_2,value) values(to_date(:1,$fmt),:2,:3,:4,:5,:6,:7)" ) + || die $ora_errst; + +$this_host = 'epicsg.desy.de'; +$port = 3999; +$server_addr = (gethostbyname($this_host))[4]; +$server_struct = pack("S n a4 x8", AF_INET, $port, $server_addr); +$proto = (getprotobyname('tcp'))[2]; +socket(SOCK, PF_INET, SOCK_STREAM, $proto)|| die "Failed to initialize socket: $!\n"; + +setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR,1) || die "setsockopt() failed: $!\n"; +bind(SOCK, $server_struct) || die "bind() failed: $!\n"; +listen(SOCK, SOMAXCONN) || die "listen() failed: $!\n"; + +for (;;) { + + $remote_host = accept(NEWSOCK, SOCK); + die "accept() error: $!\n" unless ($remote_host); +recv(NEWSOCK,$buf,200,$server_struct); + +#print $buf; + +($alarm_d,$alarm_t,$x,$record_name,$alarm_type_1,$alarm_1,$alarm_type_2,$alarm_2,$value) = +$buf =~/(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/; +$alarm_date = $alarm_d . ' ' . $alarm_t; +#print "$alarm_date,$alarm_t,$record_name,$alarm_type_1,$alarm_1,$alarm_type_2,$alarm_2,$value\n"; + +&ora_bind($csr_insert,$alarm_date,$record_name,$alarm_type_1,$alarm_1,$alarm_type_2,$alarm_2,$value) || die $ora_errst; +&ora_commit($lda); +} + + + + + diff --git a/test.alhConfig b/test.alhConfig new file mode 100644 index 0000000..2475da1 --- /dev/null +++ b/test.alhConfig @@ -0,0 +1,36 @@ +$BEEPSEVERITY MAJOR +GROUP NULL JBA_TEST_MAIN_GROUP +$COMMAND xload +$GUIDANCE +This is the text guidance for JBA_TEST_MAIN_GROUP alarms. +This is the text guidance for JBA_TEST_MAIN_GROUP alarms. +$END +CHANNEL JBA_TEST_MAIN_GROUP jba:Example1 ----- +CHANNEL JBA_TEST_MAIN_GROUP jba:Example2 ----- +GROUP JBA_TEST_MAIN_GROUP GROUP +$FORCEPV testjbaai -D--- 1 0 +$GUIDANCE +This is the text guidance for group GROUP. +This is the text guidance for group GROUP. +$END +$COMMAND xascii +CHANNEL GROUP jba:Example3 ----- +CHANNEL GROUP jba:Example4 ----- +GROUP GROUP SUBGROUP +$GUIDANCE +This is the text guidance for SUBGROUP. +This is the text guidance for SUBGROUP. +$END +CHANNEL SUBGROUP jba:Example5 ----- +CHANNEL SUBGROUP jba:Example6 ----- +GROUP GROUP SECONDSUBGROUP +$GUIDANCE +This is the text guidance for SECONDSUBGROUP. +This is the text guidance for SECONDSUBGROUP. +$END +CHANNEL SECONDSUBGROUP jba:Example7 ----- +CHANNEL SECONDSUBGROUP jba:Example8 ----- +GROUP JBA_TEST_MAIN_GROUP SECONDGROUP +$ALIAS This is a test alias for the second group +CHANNEL SECONDGROUP jba:Example9 ----- +CHANNEL SECONDGROUP jba:Example10 ----- diff --git a/test.win32.alhConfig b/test.win32.alhConfig new file mode 100644 index 0000000..f511971 --- /dev/null +++ b/test.win32.alhConfig @@ -0,0 +1,39 @@ +$BEEPSEVERITY MAJOR +GROUP NULL JBATestMainGroup +$COMMAND command /K dir +$GUIDANCE +This is the text guidance for JBATestMainGroup alarms. +This is more guidance for JBATestMainGroup alarms. +$END +CHANNEL JBATestMainGroup jba:Example1 ----- +CHANNEL JBATestMainGroup jba:Example2 ----- +GROUP JBATestMainGroup Group1 +$GUIDANCE +This is the text guidance for group Group1. +This is more guidance for group Group1. +$END +$COMMAND start probe.exe +CHANNEL Group1 jba:Example3 ----- +CHANNEL Group1 jba:Example4 ----- +GROUP Group1 Group1.SubGroup1 +$GUIDANCE +This is the text guidance for Group1.SubGroup1. +This is more guidance for Group1.SubGroup1. +$END +CHANNEL Group1.SubGroup1 jba:Example5 ----- +CHANNEL Group1.SubGroup1 jba:Example6 ----- +GROUP Group1 Group1.SubGroup2 +$GUIDANCE +This is the text guidance for Group1.SubGroup2. +This is more guidance for Group1.SubGroup2. +$END +CHANNEL Group1.SubGroup2 jba:Example7 ----- +CHANNEL Group1.SubGroup2 jba:Example8 ----- +GROUP JBATestMainGroup Group2 +$ALIAS AliasForGroup2 +CHANNEL Group2 jba:Example9 ----- +CHANNEL Group2 jba:Example10 ----- +GROUP JBATestMainGroup EvansGroup +CHANNEL EvansGroup evans:calc +CHANNEL EvansGroup evans:bo01 +CHANNEL EvansGroup Xorbit:S1A:H1:CurrentAO diff --git a/version.h b/version.h new file mode 100644 index 0000000..d97b938 --- /dev/null +++ b/version.h @@ -0,0 +1,38 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 Deutches Elektronen-Synchrotron in der Helmholtz- +* Gemelnschaft (DESY). +* Copyright (c) 2002 Berliner Speicherring-Gesellschaft fuer Synchrotron- +* Strahlung mbH (BESSY). +* Copyright (c) 2002 Southeastern Universities Research Association, as +* Operator of Thomas Jefferson National Accelerator Facility. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ +/* version.h */ + +/************************DESCRIPTION*********************************** + * Alarm Handler Version and Credits Information +**********************************************************************/ + +#ifndef INCversionh +#define INCversionh 1 + +#define ALH_VERSION 1 +#define ALH_REVISION 2 +#define ALH_MODIFICATION 24 + +#define ALH_VERSION_STRING "ALH Version 1.2.24" + +#define ALH_CREDITS_STRING \ + "Developed at Argonne National Laboratory\n\n" \ + "Authors: Ben-Chin Cha, Janet Anderson,\n" \ + " Mark Anderson, Marty Kraimer,\n" \ + " and Albert Kagarmanov\n\n" \ + "(With SNS modifications as of 3/07 by\n" \ + "John Sinclair and Kay Kasemir)\n\n" + +#endif /* INCversionh */