diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/appmon | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/appmon')
50 files changed, 11142 insertions, 0 deletions
diff --git a/lib/appmon/AUTHORS b/lib/appmon/AUTHORS new file mode 100644 index 0000000000..b727dae36d --- /dev/null +++ b/lib/appmon/AUTHORS @@ -0,0 +1,5 @@ +Original Authors and Contributors: + +Peter Lundell +Stefan Anbratt +Gunilla Arendt diff --git a/lib/appmon/BUGS_AND_FIXES b/lib/appmon/BUGS_AND_FIXES new file mode 100644 index 0000000000..fdac7f34c5 --- /dev/null +++ b/lib/appmon/BUGS_AND_FIXES @@ -0,0 +1,5 @@ + +***) reverse the list of children for a process, to match the starting +order. + +***) diff --git a/lib/appmon/Makefile b/lib/appmon/Makefile new file mode 100644 index 0000000000..62033ab92e --- /dev/null +++ b/lib/appmon/Makefile @@ -0,0 +1,33 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Macros +# ---------------------------------------------------- + +SUB_DIRECTORIES = src priv doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk + diff --git a/lib/appmon/doc/html/.gitignore b/lib/appmon/doc/html/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/appmon/doc/html/.gitignore diff --git a/lib/appmon/doc/man3/.gitignore b/lib/appmon/doc/man3/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/appmon/doc/man3/.gitignore diff --git a/lib/appmon/doc/pdf/.gitignore b/lib/appmon/doc/pdf/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/appmon/doc/pdf/.gitignore diff --git a/lib/appmon/doc/src/Makefile b/lib/appmon/doc/src/Makefile new file mode 100644 index 0000000000..ece0977810 --- /dev/null +++ b/lib/appmon/doc/src/Makefile @@ -0,0 +1,117 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(APPMON_VSN) +APPLICATION=appmon + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = appmon.xml + +XML_PART_FILES = \ + part.xml \ + part_notes.xml + +XML_CHAPTER_FILES = \ + appmon_chapter.xml \ + notes.xml + +BOOK_FILES = book.xml + +GIF_FILES = \ + app_win.gif \ + listbox_win.gif \ + main_win.gif \ + pinfo_win.gif \ + note.gif + +# ---------------------------------------------------- + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + rm -f $(JD_HTML) $(JD_PACK) + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 + +release_spec: + diff --git a/lib/appmon/doc/src/app_win.gif b/lib/appmon/doc/src/app_win.gif Binary files differnew file mode 100644 index 0000000000..06f21d04a9 --- /dev/null +++ b/lib/appmon/doc/src/app_win.gif diff --git a/lib/appmon/doc/src/app_win.ps b/lib/appmon/doc/src/app_win.ps new file mode 100644 index 0000000000..73d4cad278 --- /dev/null +++ b/lib/appmon/doc/src/app_win.ps @@ -0,0 +1,680 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (./app_win.tmp.eps) +%%CreationDate: (Tue Jun 12 17:59:02 2001) +%%BoundingBox: 0 46 300 384 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Pages: 0 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/buffer 512 string def +/byte 1 string def +/color_packet 3 string def +/pixels 768 string def + +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-RunlengthEncodedCompression or 1-NoCompression. + % hex color packets. + % + gsave + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 46 300 384 +userdict begin +%%BeginData: +DisplayImage +0 46 +300.000000 338.000000 +12 +382 431 +1 +0 +0 +16 +ffffff +000000 +e8e3dc +708090 +b03060 +d9d9d9 +b3b3b3 +7f7f7f +a3a3a3 +828282 +000000 +000000 +000000 +000000 +000000 +000000 +04ff04ff04ff04de05000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500041a050c04d1050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000408 +050c04050500040a0500040a050104030505040105050401050104040501040305030403 +050104020501044a05010400050104000501040005010411050104050504040205010404 +050104050501040005010409050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000407050004020500040205000402 +050004050500040a05000409050304020501040205010400050104020501040005010404 +050104020501040105010402050204010501044a05010403050104000501041105010403 +050104040500040805010408050104080500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004080500040205000402 +050004020500040505000403050204030500040905000401050004020501040205010400 +050104020501040005020402050204010501040305010401050204010501040105010404 +050004000502040005020401050104020501040105030401050104000501040105010400 +050104060503040105010400050104060501040005010400050104000501040005010400 +050104020503040105010400050504020500040605000400050104010501040005010400 +050104000503040005010409050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000407050004020500040205000402 +050004050500040205040402050004080501040105010401050104020501040005010402 +050104000502040205020401050104030501040105010400050004000501040105010404 +050104010501040105010400050104020501040005010401050104000502040005010400 +050204000501040405010401050104000502040005010404050104000502040005010400 +050104000502040005010400050104010501040005040400050104020500040205010400 +050004000500040005010400050104000502040005060400050104080500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004080504040205000402050004050500040105060401050004080501040105010401 +050504010505040105030400050304010501040305010401050104000500040005010408 +050104010501040105010401050104000501040505010400050104010501040005010401 +050104040501040105010400050104010501040405010401050104000501040005010400 +050104010501040005010401050104000502040205010402050004010500040105000401 +050004000501040005010401050104000502040105010400050104090500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004070500040605000402050004050500040105060401050004080505040105010405 +050104050501040005000400050004000501040105010403050104010501040105020408 +050104010501040105010401050104000501040205040400050104010501040005010401 +050104040501040105010400050104010501040405010401050104000501040005010400 +050104010501040005050400050104030501040205000400050004020500040105000400 +050104000501040105010400050104020501040005010408050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000408 +050004060500040205000405050004010506040105000407050104030501040005010405 +050104050501040005020400050104010501040305010401050104010502040805010401 +050104010501040205020402050104010501040005010401050104000501040105010404 +050104010501040005010401050104040501040105010400050104000501040005010401 +050104000501040405010403050104020500040005000401050104000500040105010400 +050104010501040005010402050104000501040905000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040705000406 +050004020500040505000402050404020500040705010403050104000501040505010405 +050104010500040105010402050104010501040205010402050104010501040405010401 +050104010501040205020402050104010501040005020400050104000502040005010404 +050104010501040005010401050104040501040005020400050104000501040005020400 +050104000501040105010400050104030501040005000400050004010501040005010402 +050104000501040005020400050104020501040005010408050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000408 +050804020500040505000403050204030500040705010403050104000501040505010405 +050104010500040105010403050304030501040205010401050104040501040105010401 +050104030501040305020400050304000501040105010400050104060503040105010401 +050104050501040005010400050104000501040005010400050104020503040105010404 +050104020500040805010401050104000501040005010402050104000501040905000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +05000400050004070500040a050004050500040a050004530500040a0501040405010442 +050404200500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004080500040a050004050500040a050004520501040a +050104040501046905000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +05000400050004000500040005000400050004070500040a05000405050c04510501040b +050104040501046805000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +0500040005000400050004000500040005000408050c04e5050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +050004000500040005000400050004000500040005000400050004000500040005000400 +0500040005000400050004000500040005000400050004000500040005000400050004ff +04ff04ff041303ff03ff03fb00ff00ff00fa0900000105ff05790901000105ff05790901 +000105ff05790901000105ff05790901000105ff05790901000105040104050401000503 +010205120102050b01000506010005ff051801000502010005090102050c090100010504 +0100050f01000511010005020100050a010005ff0520010005020100050b0100050c0901 +000105040100050601020505010005030102050a01000502010005010100050001010502 +0104050201020503010205020100050001010503010205ff050301000502010005020102 +050501000502010005000101050509010001050401000508010005050100050201000502 +010005090100050201000501010105010100050301000506010005020100050201000501 +010105010100050101000502010005ff0502010005020100050101000502010005040100 +050201010501010005040901000105040103050501000505010005020100050201000509 +010005020100050101000502010005030100050601000502010005020100050101000502 +01000501010005ff05060104050101000502010005040100050201000502010005040901 +000105040100050801000505010005020104050901000502010005010100050201000503 +010005060100050201000502010005010100050201000502010205ff0503010005020100 +050101040504010005020100050201000504090100010504010005080100050501000502 +0100050d0100050201000501010005020100050301000506010005020100050201000501 +0100050201000505010005ff050201000502010005010100050801000502010005020100 +050409010001050401000508010005050100050201000502010005090100050201000501 +010105010100050301000506010005020100050201000501010005020100050101000502 +010005ff0502010005020100050101000502010005040100050201010501010005040901 +000105040100050801000505010005030102050b01020502010005000101050501010504 +01000503010205020100050201000502010205ff05030100050201000502010205050100 +0502010005000101050509010001052f010005ff053e0100050809010001052f010005ff +053e0100050809010001052f010005ff053e010005080901000105ff05790901000105ff +05790901000105ff05790901000109ff097b000009ff097c02ff02ff02ff02ff02ff02ff +02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02730800000008000000080000000800 +000008000000080000000800000008000000080000000800000008000000080000000800 +000008000000080000000800000008000000080000000800000008000000080000000800 +000008000000080000000800000008000000080000000800000008000000080000000800 +000008000000080000000800000008000000020900450209004502090045024700000800 +000008000000080000000800000008000000080000000800000008000000080000000800 +000008000000080000000800000008000000080000000800000008000000080000000800 +000008000000080000000800000008000000080000000800000008000000080000000800 +000008000000080000000800000008000000080000000800000008000209004409000209 +004409000209004409000247080000000842010002090001054109010209000105410901 +020900010541090102470000084201000800020900010541090102090001054109010209 +000105410901024708000000084201000209000105410901020900010541090102090001 +054109010247000008420100080002090001054109010209000105410901020900010541 +090102470800000008120104080b0101081c010002090001051301020514010005140901 +02090001050e0104052d0901020900010512010005020100050401000503010205030102 +051509010247000008150100080c0100081d010008000209000105120100050201000513 +0100051409010209000105100100052f0901020900010512010005010100050c01000505 +010005150901024708000000081401000803010008000101080401000804010208160100 +020900010512010005060102050201000500010105030101050001000514090102090001 +051001000503010005000101050301020503010205030102051209010209000105120100 +050001000504010205050100050501000515090102470000081501000803010108010100 +080101040801010008020100081401000800020900010513010005040100050201000501 +010105010100050101000501010105140901020900010510010005030101050101000501 +010005020100050101000502010005010100050201000511090102090001051201010507 +010005050100050501000515090102470800000008140100080301000802010008030100 +080301000802010008150100020900010514010105020100050201000501010005020100 +050101000502010005140901020900010510010005030100050901000501010005050100 +050201000511090102090001051201000500010005060100050501000505010005150901 +024700000815010008030100080201000803010008030100080201000814010008000209 +000105160100050101040501010005020100050101000502010005140901020900010510 +010005030100050601030501010005050104051109010209000105120100050101000505 +010005050100050501000515090102470800000008140100080301000802010008030100 +080301000802010008150100020900010512010005020100050101000505010005020100 +050101000502010005140901020900010510010005030100050501000502010005010100 +050501000515090102090001051201000501010005050100050501000505010005150901 +024700000815010008030100080201000803010008030100080201000814010008000209 +000105120100050201000501010005020100050101000502010005010100050101010514 +090102090001051001000503010005050100050201000501010005020100050101000502 +010005110901020900010512010005020100050401000505010005050100051509010247 +080000000812010408010100080201000803010008040102081601000209000105130102 +050301020502010005020100050201010500010005140901020900010510010005030100 +050601030502010205030102051209010209000105120100050201000504010005050100 +050501000515090102470000084201000800020900010541090102090001054109010209 +000105410901024708000000084201000209000105410901020900010541090102090001 +054109010247000008420100080002090001054109010209000105410901020900010541 +090102470800000008420100020900010541090102090001054109010209000105410901 +024700000842010008000209000105410901020900010541090102090001054109010247 +080000000842010002090001054109010209000105410901020900010541090102470000 +084201000800020900010541090102090001054109010209000105410901024708000000 +084201000209000105410901020900010541090102090001054109010247000008000100 +080001000800010008000100080001000800010008000100080001000800010008000100 +080001000800010008000100080001000800010008000100080001000800010008000100 +080001000800010008000100080001000800010008000100080001000800010008000100 +080001000800010008000100080001000800010008000100080002090001094302090001 +094302090001094302470800010008000100080001000800010008000100080001000800 +010008000100080001000800010008000100080001000800010008000100080001000800 +010008000100080001000800010008000100080001000800010008000100080001000800 +010008000100080001000800010008000100080001000800010008000100080001000800 +01000800010002090000094402090000094402090000094402ff02ff02ff02ff02ff02ff +02ff02ff02ff02ff02ff02ff02ff02ff02ff022901ff017d05ff05ff05ff05ff05ff05ff +05ff05ff05ff05ff05ff05ff05ff056d02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff +02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff +02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff +02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff +02ff02ff02ff02d5014902ff023301000647010002ff023301000647010002ff02330100 +0647010002ff023301000647010002ff02330100060e0103060701010603010306020103 +060601030610010002ff02330100060d0101060101010604010306020101060101010600 +0101060101010604010106010101060f010002ff02330100060d01010601010106060101 +060201010601010106000101060101010604010106010101060f010002ff02330100060a +010106000101060101010606010106020101060101010600010106010101060401010601 +010106010101060b010002ff023301000608010206010101060101010606010106020101 +0601010106000101060101010604010106010101060201020609010002ff023301000607 +010106030101060101010606010106020101060101010600010106010101060401010601 +0101060401010608010002ff023301000608010206010101060101010606010106020101 +0601010106000101060101010604010106010101060201020609010002ff02330100060a +010106000101060101010601010106020101060201010601010106000101060101010601 +0101060001010601010106010101060b010002ff02330100060e01030602010106020101 +060301030602010306020101060101030610010002ff023301000647010002ff02330100 +0647010002ff023301000647010002ff023301000647010002ff023301000647010002ff +023301000647010002ff023301220701012402ff0256070102ff027b070102ff027b0701 +02ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b0701 +02ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b0701 +02ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b0701 +02ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b0701 +02ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b0701 +02ff027b070102ff0258014902ff023301000647010002ff023301000647010002ff0233 +01000647010002ff023301000647010002ff02330100060e010306070101060301030603 +0101060701030610010002ff02330100060d010106010101060401030602010106010101 +060001030606010106010101060f010002ff02330100060d010106010101060601010602 +010106010101060201010606010106010101060f010002ff02330100060a010106000101 +0601010106060101060201010601010106020101060601010601010106010101060b0100 +02ff02330100060801020601010106010101060601010602010106010101060201010606 +010106010101060201020609010002ff0233010006070101060301010601010106060101 +0602010106010101060201010606010106010101060401010608010002ff023301000608 +010206010101060101010606010106020101060101010602010106060101060101010602 +01020609010002ff02330100060a01010600010106010101060101010602010106020101 +060101010602010106030101060001010601010106010101060b010002ff02330100060e +01030602010106020101060301030603010106030101060101030610010002ff02330100 +0647010002ff023301000647010002ff023301000647010002ff023301000647010002ff +023301000647010002ff023301000647010002ff023301220701012402ff0256070102ff +027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff +027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff +027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff +027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff +027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff +027b070102ff027b070102ff027b070102ff0258014902ff023301000647010002ff0233 +01000647010002ff023301000647010002ff023301000647010002ff0233010006470100 +02ff023301000647010002ff023301000600010006000102060001020601010106020101 +060101030601010106000101060101010600010106090103060101010601010106000101 +060001010604010002ff0233010006000101060101010601010106000101060201010600 +010106010101060001020600010106000102060001010607010106010101060001010601 +010106000102060001010603010002ff0233010006000101060101010601010106010101 +060001010605010106000101060101010600010106010101060701020603010106010101 +06000101060101010603010002ff02330100060001010601010106010101060101010600 +010106020104060001010601010106000101060101010609010206010101060101010600 +0101060101010603010002ff023301000600010106010101060101010602010206020101 +0601010106000101060101010600010106010101060a0102060001010601010106000101 +060101010603010002ff0233010006000101060101010601010106020102060201010601 +010106000102060001010600010206000101060701010601010106000101060001020600 +0102060001010603010002ff023301000600010106010101060101010603010106030102 +060001030600010106010101060001010609010306020101060001010600010106000101 +0604010002ff02330100060e0100060a010106040101061901010607010002ff02330100 +060d0101060a010106040101061901010607010002ff02330100060c0101060b01010604 +010106040106060d01010607010002ff023301000647010002ff023301000647010002ff +023301000647010002ff023301220701012402ff0256070102ff027b070102ff027b0701 +02ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b0701 +02ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b0701 +02ff0254074802ff0233074902ff023307010245070102ff023307010245070102ff0233 +07010245070102ff023307010245070102ff023307010245070102ff0233070102450701 +02ff023307010245070102ff023307010245070102ff023307010245070102ff02330701 +0245070102ff023307010245070102ff023307010245070102ff023307010245070102ff +023307010245070102ff023307010245070102ff023307010245070102ff023307010245 +070102ff021e012d0212013b02ff02000100062b0100021201000639010002ff02000100 +062b0100021201000639010002ff02000100062b0100021201000639010002ff02000100 +062b0100021201000639010002ff02000100062b010002120100063201010604010002ff +02000100062b010002120100063201010604010002ff0200010006000100060001020600 +010206010101060201010601010306010101060101010600010106000101060401000212 +010006010100060001020600010206010101060201010601010306010101060201010601 +01030601010106000101060101030603010002ff02000100060001010601010106010101 +060001010602010106000101060101010600010106010101060001020600010106030100 +021201000601010106010101060101010600010106020101060001010601010106000101 +0602010106000101060101010600010206000101060101010604010002ff020001000600 +010106010101060101010601010106000101060101020603010106010101060001010601 +010106030100021201000601010106010101060101010601010106000101060101010601 +0101060101010600010106010101060101010600010106010101060101010604010002ff +020001000600010106010101060101010601010106000101060301020601010106010101 +060001010601010106030100021201000601010106010101060101010601010106000101 +060101050601010106000101060101050600010106010101060101010604010002ff0200 +010006000101060101010601010106020102060501020600010106010101060001010601 +010106030100021201000601010106010101060101010602010206020101060601020602 +01010604010106010101060101010604010002ff02000100060001010601010106010101 +060201020602010106010101060001010600010206000102060001010603010002120100 +060101010601010106010101060201020602010106010101060201020602010106010101 +060001010601010106010101060001000602010002ff0200010006000101060101010601 +010106030101060301030602010106000101060001010600010106040100021201000601 +010106010101060101010603010106030103060401000604010306010101060101010602 +01010603010002ff02000100060e0100061101010607010002120100060f010006280100 +02ff02000100060d0101061101010607010002120100060e01010628010002ff02000100 +060c0101061201010607010002120100060d01010629010002ff02000100062b01000212 +01000639010002ff02000100062b0100021201000639010002ff02000100062b01000212 +01000639010002ff02000114070101160212013b02ff0215070102ff027b070102ff027b +070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b +070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b070102ff027b +070102ff025c074b02ff0230074c02ff023007010248070102ff023007010248070102ff +023007010248070102ff023007010248070102ff023007010248070102ff023007010248 +070102ff023007010248070102ff023007010248070102ff023007010248070102ff0230 +07010248070102ff023007010248070102ff023007010248070102ff0230070102480701 +02ff023007010248070102ff023007010248070102ff023007010248070102ff02300701 +0248070102ff021001420212012d02f901000640010002120100062b010002f901000640 +010002120100062b010002f901000640010002120100062b010002f90100064001000212 +0100062b010002f901000640010002120100061401020613010002f90100064001000212 +0100061301010615010002f9010006020100060001020600010206010101060201010601 +010306020103060101010600010306020101060101030601010106000101060301000212 +010106000102060001020601010106020101060001030601010306010100060001020600 +01020603010002f901000602010106010101060101010600010106020101060001010601 +010106000101060101010600010606020101060001010601010106000104060301000212 +010206010101060101010600010106020101060101010601010106010101060001010601 +0101060101010602010002f9010006020101060101010601010106010101060001010601 +010206030101060101010600010206020101060001010601010106010101060001020605 +010002120102060101010601010106010101060001010602010106010102060301010601 +0101060101010602010002f9010006020101060101010601010106010101060001010603 +010206010105060001010603010106000101060101050600010106060100021201020601 +010106010101060101010600010106020101060301020601010106010101060101010602 +010002f90100060201010601010106010101060201020605010206000101060401010604 +010206020101060401010606010002120102060101010601010106020102060301010604 +01020600010106010101060101010602010002f901000602010106010101060101010602 +010206020101060101010600010106010101060001010604010206020101060101010600 +010106060100021201020601010106010101060201020603010106010101060101010600 +010106010101060101010602010002f90100060201010601010106010101060301010603 +010306020103060101010605010006040103060101010606010002120102060101010601 +01010603010106030101060201030601010106010101060101010602010002f901000610 +0100062e010002120100060d0100061c010002f90100060f0101062e010002120100060c +0101061c010002f90100060e0101062f010002120100060b0101061d010002f901000640 +010002120100062b010002f901000640010002120100062b010002f90100064001000212 +0100062b010002f901420212012d02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff +02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff +02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff +02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff02ff +02ff0236 +%%EndData +end +%%PageTrailer +%%Trailer +%%BoundingBox: 0 46 300 384 +%%EOF diff --git a/lib/appmon/doc/src/appmon.xml b/lib/appmon/doc/src/appmon.xml new file mode 100644 index 0000000000..1acb1eb6fa --- /dev/null +++ b/lib/appmon/doc/src/appmon.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + </legalnotice> + + <title>appmon</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>appmon</module> + <modulesummary>A graphical node and application process tree viewer.</modulesummary> + <description> + <p>The application monitor Appmon is a graphical utility used to + supervise applications executing either locally or on remote nodes. + The process tree of an application can furthermore be monitored.</p> + </description> + <funcs> + <func> + <name>start()</name> + <fsummary>Start Appmon.</fsummary> + <desc> + <p>Starts Appmon.</p> + </desc> + </func> + <func> + <name>stop()</name> + <fsummary>Stop Appmon.</fsummary> + <desc> + <p>Stops Appmon.</p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p>Appmon User's Guide</p> + </section> +</erlref> + diff --git a/lib/appmon/doc/src/appmon_chapter.xml b/lib/appmon/doc/src/appmon_chapter.xml new file mode 100644 index 0000000000..9673a13078 --- /dev/null +++ b/lib/appmon/doc/src/appmon_chapter.xml @@ -0,0 +1,322 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Appmon</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>appmon_chapter.xml</file> + </header> + + <section> + <title>Introduction</title> + <p>The application monitor Appmon is a graphical node and application viewer. The tool shows an overview of all applications on all known nodes, and it is possible to view the process tree for an application running on any of the nodes.</p> + <note> + <p>If the Appmon code is not available at a node, for example an + embedded node, this node is ignored by Appmon and is not shown + in the Appmon window.</p> + </note> + </section> + + <section> + <title>Getting Started with Appmon</title> + <p>Start Appmon by calling <c><![CDATA[appmon:start()]]></c>. It will start the <seealso marker="#main_win">main window</seealso> showing a load meter and the applications running at the current node. By clicking on one of the applications a window showing the process tree of the application will be opened, the <seealso marker="#app_win">application window</seealso>.</p> + <p>The main window is equipped with a menubar from which it is possible to:</p> + <list type="bulleted"> + <item>exit Appmon</item> + <item>perform some operations on the node</item> + <item>set how information should be displayed</item> + <item>select which node to show</item> + <item>open help (this document).</item> + </list> + <p>The application window shows the process tree for an application with each process displayed as a box. It is possible to view information about the processes, to send messages to them, and to trace and kill them.</p> + </section> + + <section> + <title>The Main Window</title> + <marker id="main_win"></marker> + <p>The main window shows a load meter and all applications running at the displayed node. Select which node to display in the window by choosing the node name from the Nodes menu. It is also possible to run Appmon in a many-window mode where a new instance of the main window is opened for each node to be displayed.</p> + <image file="main_win.gif"> + <icaption>The Main Window.</icaption> + </image> + <p>The load meter shows load measured as processor time, or as the length of the ready queue.</p> + <p>Every application running at the node is shown as a button. Clicking the button will open the application window showing the process tree for the application.</p> + + <section> + <title>The File Menu</title> + <taglist> + <tag><em>Show List Box...</em></tag> + <item>This will open the <seealso marker="#listbox_win">listbox window</seealso> which lists all nodes and applications. This window can be more easy to use than the normal, graphical user interface when the system consists of a large number of nodes and/or applications.</item> + <tag><em>Close</em></tag> + <item>Close the window. If no other instance of the main window exists, Appmon will be stopped.</item> + <tag><em>Exit</em></tag> + <item>Stop Appmon.</item> + </taglist> + </section> + + <section> + <title>The Actions Menu</title> + <taglist> + <tag><em>Reboot</em></tag> + <item>Call <c><![CDATA[init:reboot()]]></c> at the currently displayed node. This will stop the node. If the <c><![CDATA[-heart]]></c> system flag was given, the heart program will try to reboot the system.</item> + <tag><em>Restart</em></tag> + <item>Call <c><![CDATA[init:restart()]]></c> at the currently displayed node. This will restart the node.</item> + <tag><em>Stop</em></tag> + <item>Call <c><![CDATA[init:stop()]]></c> at the currently displayed node. This will stop the node.</item> + <tag><em>Ping</em></tag> + <item>Call <c><![CDATA[net:ping(Node)]]></c> where <c><![CDATA[Node]]></c> is the currently displayed node. This can be useful when the connection to the node has been lost.</item> + </taglist> + </section> + + <section> + <title>The Options Menu</title> + <taglist> + <tag><em>One window/Many windows</em></tag> + <item>Select one of these radio button to run Appmon in one-window or many-window mode. In many-windows mode, a new instance of the main window is opened for each node to be displayed. The default value is one-window mode.</item> + <tag><em>Load: time/queue</em></tag> + <item>Select one of these radio buttons to either calculate load as processor time or as the length of the ready queue, which is the number of processes ready to execute. By default, the load is calculated as processor time.</item> + <tag><em>Load: progressive/linear</em></tag> + <item>Select one of these radio buttons to show load either according to a progressive or a linear scale. By default, the load is shown according to a progressive scale. </item> + </taglist> + </section> + + <section> + <title>The Nodes Menu</title> + <p>The Nodes menu contains all currently and previously known nodes, + where the Appmon code is available. Nodes where the Appmon code is + not available, for example embedded nodes, are ignored by Appmon and + are not shown.</p> + <p>Selecting a node from the Nodes menu will cause that node to be displayed in either the same window, or in a new window, depending on if Appmon is run in one-window or many-windows mode. If the connection to the node has been lost, this will be shown in the window.</p> + </section> + + <section> + <title>The Help Menu</title> + <taglist> + <tag><em>Help</em></tag> + <item>Selecting Help from the Help menu will cause the HTML version of the Appmon User's Guide (this document) to be displayed. Currently this function requires Netscape to be up and running.</item> + </taglist> + </section> + </section> + + <section> + <title>The Application Window</title> + <marker id="app_win"></marker> + <p>The application window shows the process tree for an application. The window title contains the application name and the node name. The window also contains a menubar and a toolbar.</p> + <p>The application window can be opened from the main window by clicking on the button denoting the application, or from the listbox window by selecting the application and clicking on the <em>Load</em> button. + </p> + <image file="app_win.gif"> + <icaption>The Application Window.</icaption> + </image> + <p>The application can be shown either as a strict supervision tree, or as a process view with all linked processes. In supervision mode, the tree-gathering and -building algorithm assumes conformance to the OTP design principles.</p> + + <section> + <title>The File Menu</title> + <taglist> + <tag><em>Close</em></tag> + <item>Close the application window.</item> + </taglist> + </section> + + <section> + <title>The Options Menu</title> + <taglist> + <tag><em>Refresh</em></tag> + <item>Refresh the application window.</item> + <tag><em>Sup. view/ Proc. view</em></tag> + <item>Select one of these radio buttons to show the application as a strict supervision tree, or as a process view with all linked processes. By default, the process view is used.</item> + </taglist> + </section> + + <section> + <title>The Toolbar</title> + <p>The toolbar consists of four buttons: <em>Info</em>, <em>Send</em>, <em>Trace</em> and <em>Kill</em>. First select one of these buttons and then select to which process the action should apply by clicking on a process in the process tree. By default <em>Info</em> is selected which means that clicking on a process, without selecting <em>Send</em>, <em>Trace</em> or <em>Kill</em> first, will open the <seealso marker="#pinfo_win">process information window</seealso>.</p> + <taglist> + <tag><em>Info</em></tag> + <item>Open the <seealso marker="#pinfo_win">process information window</seealso>, which displays the information about the process given by <c><![CDATA[process_info(Pid)]]></c>.</item> + <tag><em>Send</em></tag> + <item>Send a message to a process. A window is opened where the message can be specified. Click <em>Ok</em> to send the message or <em>Cancel</em> to cancel.</item> + <tag><em>Trace</em></tag> + <item>Switch on OTP tracing of a process. <c><![CDATA[sys:trace(Pid,true)]]></c> is called. Selecting <em>Trace</em> a second time for the same process will switch the tracing off instead.</item> + <tag><em>Kill</em></tag> + <item>Kill a process. <c><![CDATA[exit(Pid,kill)]]></c> is called.</item> + </taglist> + </section> + </section> + + <section> + <title>The Listbox Window</title> + <marker id="listbox_win"></marker> + <p>The listbox window lists all nodes and applications. This window can be more easy to use than the normal, graphical user interface when the system consists of a large number of nodes and/or applications.</p> + <image file="listbox_win.gif"> + <icaption>The Listbox Window.</icaption> + </image> + <p>The window contains three buttons:</p> + <taglist> + <tag><em>Load</em></tag> + <item>First selecting an application and then clicking the <em>Load</em> button will open the <seealso marker="#app_win">application window</seealso> for that application.</item> + <tag><em>Clear</em></tag> + <item>De-select any selected node or application name.</item> + <tag><em>Close</em></tag> + <item>Close the listbox window.</item> + </taglist> + </section> + + <section> + <title>The Process Information Window</title> + <marker id="pinfo_win"></marker> + <p>The process information window shows information about different processes as given by <c><![CDATA[process_info(Pid)]]></c>.</p> + <image file="pinfo_win.gif"> + <icaption>The Process Information Window.</icaption> + </image> + + <section> + <title>The File Menu</title> + <taglist> + <tag><em>Close</em></tag> + <item>Close the process information window.</item> + </taglist> + </section> + </section> + + <section> + <title>Using the Web Based version of Appmon</title> + + <section> + <title>Introduction</title> + <p>The web based version of Appmon is an alternative version of + Appmon. The main difference between the web based version of + Appmon and the original version of Appmon is that the web based + version of Appmon can monitor nodes and applications on nodes where + Appmon not is installed.</p> + </section> + + <section> + <title>Start the Web Based version of Appmon</title> + <p>To start the web based user interface configure and start + WebTool, see <em>WebTool User's Guide</em>. The web based + version of Appmon is compatible with the browsers + Netscape Navigator and Internet Explorer 4.0 and higher.</p> + <p>When WebTool is started, start the Web based version of Appmon via + WebTool. If WebTool succeeded to start the web based version of Appmon + a link named WebAppmon will appear in the topmost frame. Click on the link and + the main frame of the browser will show two frames.The left frame will + show a combo box for node selection and a list of all applications on + the currently selected node. </p> + <p>In the left frame it is possible to:</p> + <list type="bulleted"> + <item>Select which node to supervise.</item> + <item>Select an application to view it's process tree.</item> + <item>Select an application to view it's specification.</item> + </list> + <p>The right frame shows the selected information, either the application + specification or the process tree and process information.</p> + </section> + + <section> + <title>Selecting a Different Node</title> + <p>In the top of the left frame there is a combo box with all known + nodes. The name of the node that is monitored is the node whose name + is visible in the combo box. At startup the node on which the web + based version of Appmon is running on will be monitored.</p> + <p>To change node, select another node in the combo box, and + the list of running applications will change to the applications + that runs on the selected node.</p> + </section> + + <section> + <title>Viewing the Process Tree of an Application</title> + <p>To view the process tree of an application click on the application + name in the list of applications. The process tree of the selected + application will then appear in the right frame.</p> + <p>The processes in the process tree can have three different colors:</p> + <taglist> + <tag><em>Blue</em></tag> + <item>The relation to the process above in the process hierarchy + is a primary relation. That means that the process above is the + only process that link to it or the process above is a supervisor. </item> + <tag><em>Red</em></tag> + <item>The relation to the process above in the process hierarchy is a secondary + relation. This means that more than one process has a relation to it + and the process above in the hierarchy is not a supervisor.</item> + <tag><em>Black</em></tag> + <item>The process isn't a regular process instead it's a Port. The name of + the process will also begin with <em>Port:</em></item> + </taglist> + <p>If the process name begins with <em>Runs on another node:</em> The + monitored application runs on more than one node and this process is + the first process on a branch that runs on another node. </p> + </section> + + <section> + <title>Viewing the Application Specification</title> + <p>After the application name in the list of applications there are a + link named <em>Spec</em>, Click on this link and the application + specification will appear in the right frame. The application + specification is the data in the <em>.app</em> file of the selected + application. </p> + </section> + + <section> + <title>Select Process View</title> + <p>In the top of the page that shows the process tree, there are three + radio buttons for selecting which processes that shall be included + in the process tree. The default mode is that all processes + that one process in the application tree has a relation to is + included. It's possible to filter which of the processes + in the process tree that will be included. To reduce the number + of processes in the process tree select one of the radio buttons + on the top of the page </p> + <taglist> + <tag><em>All processes</em></tag> + <item>All processes that at least one process in the application + tree has a link to.</item> + <tag><em>Supervised processes</em></tag> + <item>All processes that are supervised by one of the supervisors in + the application</item> + <tag><em>Supervisors only</em></tag> + <item>Only the processes that actually are supervisors in the + applications supervision tree is included</item> + </taglist> + </section> + + <section> + <marker id="proc_info"></marker> + <title>Process Information</title> + <p>To see more information about a specific process click on the process + name and more information will be loaded under the application tree.</p> + <p>The Process information page shows information about a process as given + by the <c><![CDATA[process_info(Pid)]]></c>, but formatted in a more human readable form.</p> + </section> + + <section> + <title>Trace a process</title> + <p>If the link after the process name in the process tree is <em>start trace</em> + the process is not traced. If the link is <em>stop trace</em> then the process + id traced.</p> + <p>To toggle the trace flag for a process click on the link <em>start trace</em> or + <em>stop trace</em> after the process name in the process tree.</p> + </section> + </section> +</chapter> + diff --git a/lib/appmon/doc/src/book.xml b/lib/appmon/doc/src/book.xml new file mode 100644 index 0000000000..df6d57c077 --- /dev/null +++ b/lib/appmon/doc/src/book.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>appmon</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev>2.0</rev> + </header> + <insidecover> + </insidecover> + <pagetext>Appmon</pagetext> + <preamble> + </preamble> + <parts lift="no"> + <xi:include href="part.xml"/> + </parts> + <applications> + <xi:include href="ref_man.xml"/> + </applications> + <releasenotes> + <xi:include href="notes.xml"/> + </releasenotes> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/lib/appmon/doc/src/fascicules.xml b/lib/appmon/doc/src/fascicules.xml new file mode 100644 index 0000000000..0678195e07 --- /dev/null +++ b/lib/appmon/doc/src/fascicules.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE fascicules SYSTEM "fascicules.dtd"> + +<fascicules> + <fascicule file="part" href="part_frame.html" entry="no"> + User's Guide + </fascicule> + <fascicule file="ref_man" href="ref_man_frame.html" entry="yes"> + Reference Manual + </fascicule> + <fascicule file="part_notes" href="part_notes_frame.html" entry="no"> + Release Notes + </fascicule> + <fascicule file="" href="../../../../doc/print.html" entry="no"> + Off-Print + </fascicule> +</fascicules> + diff --git a/lib/appmon/doc/src/listbox_win.gif b/lib/appmon/doc/src/listbox_win.gif Binary files differnew file mode 100644 index 0000000000..38258b7552 --- /dev/null +++ b/lib/appmon/doc/src/listbox_win.gif diff --git a/lib/appmon/doc/src/listbox_win.ps b/lib/appmon/doc/src/listbox_win.ps new file mode 100644 index 0000000000..0f1e2eeda0 --- /dev/null +++ b/lib/appmon/doc/src/listbox_win.ps @@ -0,0 +1,741 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (./listbox_win.tmp.eps) +%%CreationDate: (Tue Jun 12 18:01:07 2001) +%%BoundingBox: 0 85 200 356 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Pages: 0 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/buffer 512 string def +/byte 1 string def +/color_packet 3 string def +/pixels 768 string def + +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-RunlengthEncodedCompression or 1-NoCompression. + % hex color packets. + % + gsave + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 85 200 356 +userdict begin +%%BeginData: +DisplayImage +0 85 +200.000000 271.000000 +12 +325 441 +1 +0 +0 +8 +ffffff +000000 +708090 +b03060 +d9d9d9 +808080 +c3c3c3 +000000 +03ff03ff03ff036704000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +04000300040003000400030004000300040003000400031a040c03cc0400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +0400030004000308040c03050400030a0400030a04010343040103240401031904010300 +0401030f040103010401031e040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003070400030204000302 +04000302040003050400030a040003090403034204010324040103190401031204010321 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003080400030204000302040003020400030504000303 +040203030400030904000301040003010401030004010301040103000401030104000300 +040203000402030204030301040103000401030204010304040103000401030204030302 +040103000401030104030302040303060403030104010300040103020401030004010305 +040303010401030004010301040103000401030104010300040103010403030204030301 +04030300040103010403030104010300040103020403030a040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003070400030204000302040003020400030504000302040403020400030804010301 +040103000402030004010300040203000401030004010301040103010401030004010301 +040103000402030004010301040103040402030004010300040103010401030004010300 +040203000401030104010300040103010401030404010301040103000402030004010300 +040103000402030404010301040103000402030004010300040203000401030004010300 +040103000401030104010300040103010401030104010301040103000401030104010300 +040203000401030004010301040103080400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030804040302 +040003020400030504000301040603010400030804010301040103000401030104010300 +040103010401030004010301040103010401030004010301040103000401030104010308 +04010301040103000401030104010300040103010401030004010301040103000402030b +040103000401030104010300040103010401030804010300040103010401030004010301 +040103000401030004010300040103080401030104010301040103000401030104010300 +04010301040103000402030c040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003070400030604000302 +040003050400030104060301040003080405030004010301040103000401030104010300 +040103010401030104010300040103010401030004010301040103080401030104010300 +040103010401030004010301040103000405030204020306040403000401030104010300 +040103010401030504040300040103010401030004010301040103000401030004010300 +040103050404030104010301040103000401030104010300040103010401030204020309 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003080400030604000302040003050400030104060301 +040003070401030304030301040103000401030104010300040103010401030104010300 +040103010401030004010301040103080401030104010300040103010401030004010301 +040103000401030704020304040103010401030004010301040103000401030104010304 +040103010401030004010301040103000401030104010300040103000401030004010304 +040103010401030104010301040103000401030104010300040103010401030304020309 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003070400030604000302040003050400030204040302 +040003070401030304040300040103000402030004010300040103010401030104010300 +040103010401030004010301040103010401030404010301040103000401030104010300 +040103000402030004010301040103000401030104010304040103010401030004010301 +040103000401030004020304040103010401030004020300040103000402030004010300 +040103000401030004010301040103000401030104010301040103000402030004010301 +040103000401030104010300040103010401030804000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000308 +040803020400030504000303040203030400030704010303040303000401030104010300 +040103010401030104010301040103010403030104010301040103010401030404010301 +040103010403030204010300040103010403030204030306040203000403030104010301 +040103000401030504020300040303000401030104010300040103010401030004010301 +04030302040203000401030104010300040103010403030104010301040103010403030a +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003070400030a040003050400030a0400030f04010304 +0401036c040103040401033d040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003080400030a04000305 +0400030a0400030f040103040401036c040103040401033e040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003070400030a04000305040c030f040103040401036c040103040401033d04000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000308040c03e00400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +04000300040003000400030004000300040003000400030004000300040003ff03ff03a1 +02ff02ff028904ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff046b0512 +04ff043105110000047e05b0040105010606050006060001047e05af0000040105010605 +0000050006060001047e050104ac00010401050106050000050106050001047e050104ac +00010401050106040001050106050001047e0501043301000430010004260100041d0001 +04010501060400010400050106040001047e050104040100040401000403010204020100 +0415010004040100040001000405010004060100040b010004030102040b0100040b0102 +0405010004120100041c000104010501060300010401050106040001047e050104040100 +040b010004020100041501000403010004020100040c010004120100040b0100040d0100 +04190100041c000104010501060300010402050106030001047e05010401010104000100 +040201020405010004020100040001010403010204020100040001010402010404010100 +0400010204020102040301010400010004010100040001010403010204050100040a0100 +04050102040501000403010204020100040201000402010204050100041b000104010501 +060200010403050106030001047e05010400010004010101040401000405010004020101 +040101000401010004020100040101010401010004030100040301000400010004000100 +04040100040201000401010104010101040101000404010004050100040a010004040100 +0402010004040100040501000402010004020100040101000402010004040100041b0001 +04010501060200010404050106020001047e050104000100040201000404010004050100 +040201000402010004010100040201000401010004070100040301000400010004000100 +040401000402010004020100040101000408010004050100040a01000408010004040100 +040501000402010004020100040101000402010004040100041b00010401050106010001 +0405050106020001047e0501040001000402010004040100040501000402010004020100 +040101040401010004070100040301000400010204040100040201000402010004010100 +0408010004050100040a0100040501030404010004050100040301000400010004020104 +04040100041b000104010501060100010406050106010001047e05010400010004020100 +040401000405010004020100040201000401010004050100040701000403010004080100 +0402010004020100040101000408010004050100040a0100040401000402010004040100 +0405010004030100040001000402010004080100041b0001040105010600000104070501 +06010001047e050104000100040101010404010004050100040201010401010004010100 +040201000401010004070100040401000401010004040100040201000401010104010100 +0408010004050100040b0100040301000402010004040100040501000404010004030100 +0402010004030100041c000104010501060000010408050106000001047e050104010101 +040001000404010004050100040201000400010104030102040201000408010104030101 +040501000403010104000100040101000408010004050100040b01000404010304040100 +04050100040401000404010204040100041c0001040105010001050b06000001047e0501 +0465010004260100041d0001040105010000050d0001047e050104ac000104010501060e +0001047e050104ac0001040105010010047e050104ac000104010501000d05000001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104160101040001000402010004020100040201020402 +010004000101040201000400010104750001040105010001040a05010001047e05010416 +010004000100040001000401010004020100040101000402010004010101040101000401 +01010401010004740001040105010001040a05010001047e050104160100040001000400 +010004020100040101000405010004010100040201000401010004020100047400010401 +05010001040a05010001047e050104160100040001000400010004020100040101000402 +01030401010004020100040101000402010004740001040105010001040a05010001047e +050104160100040001000400010004030100040001000401010004020100040101000402 +0100040101000402010004740001040105010001040a05010001047e0501041601000400 +010004000100040301010402010004020100040101010401010004010101040101000474 +0001040105010001040a05010001047e0501041601000400010004000100040401000403 +01030401010004000101040201000400010104750001040105010001040a05010001047e +050104200100040901000405010004780001040105010001040a05010001047e0501041d +010004000100040a01000405010004780001040105010001040a05010001047e0501041e +0100040b01000405010004780001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e05010416010004220102046e00010401 +05010001040a05010001047e05010416010004240100046e0001040105010001040a0501 +0001047e0501041601000401010004030102040201000400010104020100040001010403 +010204050100046e0001040105010001040a05010001047e050104160100040001000403 +01000402010004010101040101000401010104010100040101000402010004040100046e +0001040105010001040a05010001047e0501041601010404010004020100040101000405 +010004020100040101000402010004040100046e0001040105010001040a05010001047e +050104160101040401040401010004050100040201000401010404040100046e00010401 +05010001040a05010001047e050104160100040001000403010004050100040501000402 +01000401010004080100046e0001040105010001040a05010001047e0501041601000401 +01000402010004020100040101000405010004020100040101000402010004040100046e +0001040105010001040a05010001047e0501041601000402010004020102040201000405 +0100040201000402010204050100046e0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e0501042c0102047c0001040105010001040a05010001047e +0501042e0100047c0001040105010001040a05010001047e050104170102040301020403 +010204050100047c0001040105010001040a05010001047e050104160100040201000401 +010004020100040101000402010004040100047c0001040105010001040a05010001047e +050104160100040901000401010004080100047c0001040105010001040a05010001047e +050104170102040301030402010204050100047c0001040105010001040a05010001047e +0501041a010004010100040201000405010004040100047c0001040105010001040a0501 +0001047e050104160100040201000401010004020100040101000402010004040100047c +0001040105010001040a05010001047e050104170102040301030402010204050100047c +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e0501043301000430010004260100041d0001040105010001 +040a05010001047e050104040100040f0100041501000404010004000100040501000406 +0100040b010004030102040b0100040b01020405010004120100041c0001040105010001 +040a05010001047e050104040100040f0100041501000403010004020100040c01000412 +0100040b0100040d010004190100041c0001040105010001040a05010001047e05010401 +010104000100040201020403010104000100040101000400010104030102040201000400 +010104020104040101000400010204020102040301010400010004010100040001010403 +010204050100040a01000405010204050100040301020402010004020100040201020405 +0100041b0001040105010001040a05010001047e05010400010004010101040101000402 +010004010100040101010401010104010100040101000402010004010101040101000403 +010004030100040001000400010004040100040201000401010104010101040101000404 +010004050100040a01000404010004020100040401000405010004020100040201000401 +01000402010004040100041b0001040105010001040a05010001047e0501040001000402 +010004010100040201000401010004020100040101000402010004010100040201000401 +010004070100040301000400010004000100040401000402010004020100040101000408 +010004050100040a01000408010004040100040501000402010004020100040101000402 +010004040100041b0001040105010001040a05010001047e050104000100040201000401 +010004020100040101000402010004010100040201000401010404010100040701000403 +010004000102040401000402010004020100040101000408010004050100040a01000405 +0103040401000405010004030100040001000402010404040100041b0001040105010001 +040a05010001047e05010400010004020100040101000402010004010100040201000401 +010004020100040101000405010004070100040301000408010004020100040201000401 +01000408010004050100040a010004040100040201000404010004050100040301000400 +01000402010004080100041b0001040105010001040a05010001047e0501040001000401 +010104010100040201000401010004010101040101010401010004010100040201000401 +010004070100040401000401010004040100040201000401010104010100040801000405 +0100040b0100040301000402010004040100040501000404010004030100040201000403 +0100041c0001040105010001040a05010001047e05010401010104000100040201020403 +010104000100040101000400010104030102040201000408010104030101040501000403 +010104000100040101000408010004050100040b01000404010304040100040501000404 +01000404010204040100041c0001040105010001040a05010001047e0501041201000451 +010004260100041d0001040105010001040a05010001047e0501040e0100040201000498 +0001040105010001040a05010001047e0501040f010204990001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e05010416 +010004220102046e0001040105010001040a05010001047e05010416010004240100046e +0001040105010001040a05010001047e0501041601000401010004030102040201000400 +010104020100040001010403010204050100046e0001040105010001040a05010001047e +050104160100040001000403010004020100040101010401010004010101040101000401 +01000402010004040100046e0001040105010001040a05010001047e0501041601010404 +010004020100040101000405010004020100040101000402010004040100046e00010401 +05010001040a05010001047e050104160101040401040401010004050100040201000401 +010404040100046e0001040105010001040a05010001047e050104160100040001000403 +01000405010004050100040201000401010004080100046e0001040105010001040a0501 +0001047e0501041601000401010004020100040201000401010004050100040201000401 +01000402010004040100046e0001040105010001040a05010001047e0501041601000402 +0100040201020402010004050100040201000402010204050100046e0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001047e050104ac00010401 +05010001040a05010001047e050104ac0001040105010001040a05010001047e050104ac +0001040105010001040a05010001047e050104ac0001040105010001040a05010001047e +050104ac0001040105010001040a05010001047e050104ac0001040105010001040a0501 +0001047e050104ac0001040105010001040a05010001047e050104ac0001040105010001 +040a05010001047e050104ac0001040105010001040a05010001040900630410050104ac +0001040105010001040a050100010409006205000410050104ac0001040105010001040a +0501000104090001045f05010410050104ac0001040105010001040a0501000104090001 +045f05010410050104ac0001040105010001040a0501000104090001045f050104100501 +04ac0001040105010001040a0501000104090001045f05010410050104ac000104010501 +0001040a0501000104090001045f05010410050104ac0001040105010001040a05010001 +04090001045f05010410050104ac0001040105010001040a0501000104090001045f0501 +0410050104ac0001040105010001040a0501000104090001042101000417010004230501 +0410050104ac0001040105010001040a0501000104090001042101000417010004230501 +0410050104ac0001040105010001040a0501000104090001042101000406010204030102 +0403010104000100042305010410050104ac0001040105010001040a0501000104090001 +042101000405010004020100040101000402010004010100040101010423050104100501 +04ac0001040105010001040a050100010409000104210100040501000402010004050100 +0401010004020100042305010410050104ac0001040105010001040a0501000104090001 +042101000405010004020100040201030401010004020100042305010410050104ac0001 +040105010001040a05010001040900010421010004050100040201000401010004020100 +0401010004020100042305010410050104ac0001040105010001040a0501000104090001 +042101000405010004020100040101000402010004010100040101010423050104100501 +04ac0001040105010001040a050100010409000104210104040201020403010304020101 +04000100042305010410050104ac0001040105010001040a0501000104090001045f0501 +0410050104ac0001040105010001040a0501000104090001045f05010410050104ac0001 +040105010001040a0501000104090001045f05010410050104ac0001040105010001040a +0501000104090001045f05010410050104ac0001040105010001040a0501000104090001 +045f05010410050104ac0001040105010001040a0501000104090001045f050104100501 +04ac0001040105010001040a0501000104090001045f05010410050104ac000104010501 +0001040a0501000104090001045f05010410050104ac0001040105010001040a05010001 +04090001045f05010410050104ac0001040105010001040a0501000104090001045f0501 +0410050104ac0001040105010001040a050100010409000105610410050104ac00010401 +05010001040a050100010409000005620410050104ac0001040105010001040a05010001 +047e050104ac0001040105010001040a05010001047e050104ac0001040105010001040a +05010001047e050104ac0001040105010001040a05010001047e050104ac000104010501 +0001040a05010001047e050104ac0001040105010001040a05010001047e050104ac0001 +040105010001040a05010001047e050104ac0001040105010001040a05010001047e0501 +04ac0001040105010001040a05010001047e050104ac0001040105010001040a05010001 +047e050104ac0001040105010001040a05010001040900630410050104ac000104010501 +0001040a050100010409006205000410050104ac0001040105010001040a050100010409 +0001045f05010410050104ac0001040105010001040a0501000104090001045f05010410 +050104ac0001040105010001040a0501000104090001045f05010410050104ac00010401 +05010001040a0501000104090001045f05010410050104ac0001040105010001040a0501 +000104090001045f05010410050104ac0001040105010001040a0501000104090001045f +05010410050104ac0001040105010001040a0501000104090001045f05010410050104ac +0001040105010001040a0501000104090001041e010204030102043605010410050104ac +0001040105010001040a0501000104090001041d01000402010004040100043605010410 +050104ac0001040105010001040a0501000104090001041d010004020100040401000403 +0102040301020402010004000101042105010410050104ac0001040105010001040a0501 +000104090001041d01000408010004020100040201000401010004020100040101010401 +0100042005010410050104ac0001040105010001040a0501000104090001041d01000408 +010004020100040201000405010004010100042405010410050104ac0001040105010001 +040a0501000104090001041d010004080100040201040402010304010100042405010410 +050104ac0001040105010001040a0501000104090001041d010004020100040401000402 +0100040501000402010004010100042405010410050104ac0001040105010001040a0501 +000104090001041d01000402010004040100040201000402010004010100040201000401 +0100042405010410050104ac0001040105010001040a0501000104090001041e01020405 +0100040301020403010304010100042405010410050104ac0001040105010001040a0501 +000104090001045f05010410050104ac0001040105010001040a0501000104090001045f +05010410050104ac0001040105010001040a0501000104090001045f05010410050104ac +0001040105010001040a0501000104090001045f05010410050104ac0001040105010001 +040a0501000104090001045f05010410050104ac0001040105010001040a050100010409 +0001045f05010410050104ac0001040105010001040a0501000104090001045f05010410 +050104ac0001040105010001040a0501000104090001045f05010410050104ac00010401 +05010001040a0501000104090001045f05010410050104ac0001040105010001040a0501 +000104090001045f05010410050104ac0001040105010001040a05010001040900010561 +0410050104ac0001040105010001040a050100010409000005620410050104ac00010401 +05010001040a05010001047e050104ac0001040105010001050c0001047e050104ac0001 +040105010000050d0001047e050104ac000104010501060e0001047e050104ac00010401 +05010010047e050104ac0001040105010600000c05000001047e050104ac000104010501 +060000010408050106000001047e050104ac000104010501060100010407050106000001 +047e050104ac000104010501060100010406050106010001047e050104ac000104010501 +060200010405050106010001047e050104ac000104010501060200010404050106020001 +040900630410050104ac0001040105010603000104030501060200010409006205000410 +050104ac00010401050106030001040205010603000104090001045f05010410050104ac +00010401050106040001040105010603000104090001045f05010410050104ac00010401 +050106040001040005010604000104090001045f05010410050104ac0001040105010605 +000005020604000104090001045f05010410050104ac0001040105010605000005010605 +000104090001045f05010410050100ae04010501060605010605000104090001045f0501 +0410050000af04010501060605000606000104090001045f050104c30501001004090001 +041e0102040301020436050104c30500001104090001041d010004020100040401000436 +0501040e05b804180001041d010004020100040401000403010204030102040301020421 +0501040e05b7000004180001041d01000408010004020100040201000401010004020100 +040101000402010004200501040e0501060d00000600009406000001060c000104180001 +041d010004080100040201000402010004010100040501000402010004200501040e0501 +060b0001050006000093050006000003060a000104180001041d01000408010004020100 +04020100040201020402010404200501040e050106090002050106000001049005010600 +00050608000104180001041d010004020100040401000402010004020100040501000401 +010004240501040e05010607000304000501060000010490050106000001040100030606 +000104180001041d01000402010004040100040201000402010004010100040201000401 +01000402010004200501040e050106050003040205010600000104900501060000010403 +00030604000104180001041e01020405010004030102040301020403010204210501040e +05010603000304040501060000010490050106000001040500030602000104180001045f +0501040e0501060100030406050106000001049005010600000104070003060000010418 +0001045f0501040e05050408050106000001049005010600000104080503000104180001 +045f0501040e050106010503040605010600000104900501060000010407050306000001 +04180001045f0501040e0501060305030404050106000001049005010600000104050503 +0602000104180001045f0501040e05010605050304020501060000010490050106000001 +040305030604000104180001045f0501040e050106070503040005010600000104900501 +06000001040105030606000104180001045f0501040e0501060905040600000104900501 +0600000105030608000104180001045f0501040e0501060b050206000001059206000001 +0501060a000104180001045f0501040e0501060d0500060000000593060000000500060c +000104180001045f0501040e050100b6041800010561040e050000b704180000056204ff +04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04bb +%%EndData +end +%%PageTrailer +%%Trailer +%%BoundingBox: 0 85 200 356 +%%EOF diff --git a/lib/appmon/doc/src/main_win.gif b/lib/appmon/doc/src/main_win.gif Binary files differnew file mode 100644 index 0000000000..36d742e91e --- /dev/null +++ b/lib/appmon/doc/src/main_win.gif diff --git a/lib/appmon/doc/src/main_win.ps b/lib/appmon/doc/src/main_win.ps new file mode 100644 index 0000000000..abb12d733b --- /dev/null +++ b/lib/appmon/doc/src/main_win.ps @@ -0,0 +1,691 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (./main_win.tmp.eps) +%%CreationDate: (Tue Jun 12 17:57:00 2001) +%%BoundingBox: 0 26 377 164 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Pages: 0 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/buffer 512 string def +/byte 1 string def +/color_packet 3 string def +/pixels 768 string def + +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-RunlengthEncodedCompression or 1-NoCompression. + % hex color packets. + % + gsave + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 26 377 164 +userdict begin +%%BeginData: +DisplayImage +0 26 +377.000000 138.000000 +12 +520 191 +1 +0 +0 +16 +ffffff +000000 +708090 +b03060 +d9d9d9 +808080 +00ff00 +666666 +999999 +ececc5 +000000 +000000 +000000 +000000 +000000 +000000 +03ff03ff03ff03ff03ff0305040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400031b040c03e4040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000307040c03050400030a0400030a040103030405030104050301 +040103040401030304030303040103020401030b0403031e0401032c0401030004010300 +040103000401031104010305040403020401030404010305040103000401030904000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003080400030204000302 +04000302040003050400030a040003090403030204010302040103000401030204010300 +04010304040103020401030104010302040203010401030a040103010401034c04010303 +040103000401031104010303040103040400030804010308040103080400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003070400030204000302 +040003020400030504000303040203030400030904000301040003020401030204010300 +040103020401030004020302040203010401030304010301040203010401030104010305 +040103030401030004010302040103010403030104010300040303020401030004010301 +040303010401030104010301040103050403030104010300040103060401030004010300 +040103000401030004010300040103020403030104010300040503020400030604000300 +040103010401030004010300040103000403030004010309040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030804000302040003020400030204000305 +040003020404030204000308040103010401030104010302040103000401030204010300 +040203020402030104010303040103010401030004000300040103010401030504010303 +040103000401030204010300040103010401030004060302040103000401030004010301 +040103000401030104010301040103040401030104010300040203000401030404010300 +040203000401030004010300040203000401030004010301040103000404030004010302 +040003020401030004000300040003000401030004010300040203000406030004010308 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000307 +040403020400030204000305040003010406030104000308040103010401030104050301 +040503010403030004030301040103030401030104010300040003000401030904010303 +040103010401030004010301040103010401030004020302040103000401030104010300 +040103010401030104010300040103000401030504010301040103000401030104010304 +040103010401030004010300040103000401030104010300040103010401030004020302 +040103020400030104000301040003010400030004010300040103010401030004020301 +040103000401030904000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003080400030604000302040003050400030104060301040003080405030104010305 +040103050401030004000300040003000401030104010303040103010401030104020309 +040103030401030104010300040103010405030004010303040103000401030104010300 +040503010401030004010300040103050401030104010300040103010401030404010301 +040103000401030004010300040103010401030004050300040103030401030204000300 +040003020400030104000300040103000401030104010300040103020401030004010308 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000307 +040003060400030204000305040003010406030104000307040103030401030004010305 +040103050401030004020300040103010401030304010301040103010402030904010303 +040103020402030204010304040103040402030204010300040103050401030004010300 +040103050401030104010300040103010401030404010301040103000401030004010300 +040103010401030004010304040103030401030204000300040003010401030004000301 +040103000401030104010300040103020401030004010309040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030804000306040003020400030504000302 +040403020400030704010303040103000401030504010305040103010400030104010302 +040103010401030204010302040103010401030604010301040103030402030204010301 +040103000401030404020302040103000401030104010302040103010401030604010301 +040103000401030104010304040103000402030004010300040103000402030004010300 +040103010401030004010303040103000400030004000301040103000401030204010300 +040103000402030004010302040103000401030804000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030704080302040003050400030304020303 +040003070401030304010300040103050401030504010301040003010401030304030303 +040103020401030104010307040303050400030404030301040103050400030304010301 +040303030401030104010307040303010401030104010305040103000401030004010300 +040103000401030004010302040303010401030404010302040003080401030104010300 +040103000401030204010300040103090400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +0400030004000300040003080400030a040003050400030a040003be0404032004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +04000300040003000400030004000300040003000400030004000300040003070400030a +040003050400030a040003e5040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +04000300040003080400030a04000305040c03e404000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +0400030004000300040003000400030004000307040c03f8040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +04000300040003000400030004000300040003ff03ff03ff03ff032802ff02ff02ff02ff +020f00ff00ff00ff00ff000e0500000104ff04ff04030501000104ff04ff040305010001 +04ff04ff04030501000104ff04ff04030501000104ff04ff040305010001040401040404 +01000403010204130100040c01000406010004200102040b010004060100041f01000402 +0100040c010004ff043601000402010004090102040c0501000104040100040f01000413 +0100040c01000427010004020100040a01000427010104010100040c010004ff04360100 +04020100040b0100040c0501000104040100040601020405010004030102040b01000400 +010004030102040201040402010204030102040201000400010104030102040a01000402 +01000401010004000101040201040402010204030102040201000400010104030102040a +010104010100040201020403010104000100040201020403010204ff0429010004020100 +040201020405010004020100040001010405050100010404010004080100040501000402 +010004020100040a01000400010004020100040201000403010004060100040201000402 +010004010101040101000401010004020100040901000402010004010101040101000403 +010004060100040201000402010004010101040101000401010004020100040901000400 +010004000100040101000402010004010100040101010401010004020100040101000402 +010004ff0428010004020100040101000402010004040100040201010401010004040501 +00010404010304050100040501000402010004020100040a010004000100040201000407 +0100040601000402010004020100040101000402010004010100040d0100040201000401 +01000402010004030100040601000402010004020100040101000402010004010100040d +010004000100040001000401010004020100040101000402010004010100040201000401 +010004ff042c010404010100040201000404010004020100040201000404050100010404 +010004080100040501000402010404090100040201000401010004070100040601000402 +010004020100040101000402010004020102040a01000402010004010100040201000403 +0100040601000402010004020100040101000402010004020102040a0100040101010401 +0100040201000401010004020100040101040402010204ff042901000402010004010104 +04040100040201000402010004040501000104040100040801000405010004020100040d +010404010100040701000406010004020100040201000401010004020100040501000409 +010004020100040101000402010004030100040601000402010004020100040101000402 +010004050100040901000401010104010100040201000401010004020100040101000409 +010004ff0428010004020100040101000408010004020100040201000404050100010404 +010004080100040501000402010004020100040901000402010004010100040201000403 +010004060100040201000402010004010100040201000401010004020100040901000402 +010004010101040101000403010004060100040201000402010004010100040201000401 +010004020100040901000402010004010100040201000401010004010101040101000402 +0100040101000402010004ff042801000402010004010100040201000404010004020101 +0401010004040501000104040100040801000405010004030102040a0100040201000402 +0102040501010404010004030102040201000402010004020102040b0102040201000400 +0101040501010404010004030102040201000402010004020102040a0100040201000402 +01020403010104000100040201020403010204ff04290100040201000402010204050100 +04020100040001010405050100010468010004ff048f01000408050100010468010004ff +048f01000408050100010468010004ff048f010004080501000104ff04ff040305010001 +04ff04ff04030501000104ff04ff04030501000105ff05ff0505000005ff05ff050604ff +04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff +04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff +04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04cf01ff01ff +010704ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff +04ff044c01150400010104010100041a017204ff045d0100081201010400010104000101 +041a017204ff045d01000812010404010100041a017204ff045d01000812010104000101 +04010100041a017204ff045d0100081201010400010104010100041a017204ff045d0114 +04050100041a011909010100090101000901010009010111090101050904010209010104 +09010105090101000901011704ff045d0100081201000421011909010103090101000901 +0111090101030901010409000108090101080901011704ff045d01000812010004210116 +090101000901010009010100090101000901010009010102090301010901010009050102 +090001060900010009010101090101000901010009010100090301000901011704ff045d +010008120100042101150901010009020100090101000901010009020100090101000901 +010109010100090401000901010209000102090101000900010009000100090101000901 +010009020100090601000901011704ff045d010008120100042101150901010109010100 +090101000901010009010101090101000901010109010100090201020901010209000101 +090001010900010109000100090101000901010109010100090201010901010009010117 +04ff045d0114042101150901010109010100090101000901010009010101090101000905 +010009010103090101020900010009000102090001010900010009010100090101010901 +010009010102090101000901011704ff045d010008120100042101150901010109010100 +090101000901010009010101090101000901010409010103090101020900010009000101 +090101000900010109010100090101010901010009010102090101000901011704ff045d +010008120100042101150901010009020100090101000901010009020100090101000901 +010109010100090101030901010009000100090001010901010009010102090101000901 +01000902010009010102090101000901011704ff045d0100081201000421011609010100 +090101000901010009010100090101000901010209030101090101040901010209000108 +09010101090101000901010009010102090101000901011704ff045d0100081201000421 +013d0904012f04ff045d01140421017204ff045d0100081201000421017204ff045d0100 +081201000421017204ff045d0100081201000421017204ff045d01000812010004210172 +04ff045d01140421017204ff045d01000812010004ff04f201000812010004ff04f20100 +0812010004ff04f201000812010004ff04f2011404ff04f201000812010004ff04f20100 +0812010004ff04f201000812010004ff04f201000812010004ff04f201140444010004ff +04ac0100081201000444010004ff04ac0100081201000444010004ff04ac010008120100 +0444010004ff04ac0100081201000444010004ff04ac01140444010004ff04ac01000812 +01000444010004ff04ac0100081201000444010004ff04ac0100081201000444010004ff +04ac0100081201000444010004ff04ac01140444010004ff04ac01000812010004440100 +04ff04ac0100081201000444010004ff04ac0100081201000444010004ff04ac01000812 +01000444010004ff04ac01140444010004ff04ac0100081201000444010004ff04ac0100 +081201000444010004ff04ac0100081201000444010004ff04ac01000812010004440100 +04ff04ac0114044401a004ff040c01000812010004440100044e0100044e010004ff040c +01000812010004440100044e0100044e010004ff040c01000812010004440100044e0100 +044e010004ff040c01000812010004440100044e0100044e010004ff040c011404440100 +044e0100044e010004ff040c01000812010004440100044e0100044e010004ff040c0100 +0812010004440100044e0100044e010004ff040c01000812010004440100044e0100044e +010004ff040c01000812010004440100044e0100044e010004ff040c011404440100044e +0100044e010004ff040c01000812010004440100044e0100044e010004ff040c01000812 +010004440100044e0100044e010004ff040c01000812010004440100044e0100044e0100 +04ff040c01000812010004440100044e0100044e010004ff040c011404440100044e0100 +044e010004ff040c01000812010004440100044e0100044e010004ff040c010008120100 +04440100044e0100044e010004ff040c01000812010004440100044e0100044e010004ff +040c01000812010004210045040900450409004504ea0114042000450701040700450701 +04070045070104e901000812010004200001044307010407000104430701040700010443 +070104e901000812010004200001044307010407000104430701040700010443070104e9 +01000812010004200001044307010407000104430701040700010443070104e901000812 +010004200001044307010407000104430701040700010443070104e9011404200001040f +0101041e01010410070104070001042a010104160701040700010443070104e901000612 +0101041f0001040f0101041e01010410070104070001042a010104160701040700010443 +070104e90100061201010403010204180001040f01010401010104010103040101010400 +010304000101040201030401010104100701040700010416010304020103040201030401 +01010416070104070001040d010004000102040001020401010104020101040101030401 +0101040001010401010104000101040f070104e901000612010104020101040001010417 +0001040f0101040001010401010104010101040001070400010104000101040101010400 +010104100701040700010415010104010101040001010401010104000101040101010400 +01010416070104070001040d010104010101040101010400010104020101040001010401 +010104000102040001010400010204000101040e070104e9010006120101040201010400 +010104170001040f01030402010104010101040001020401010104010101040001010401 +010104000101041007010407000104150102040701010400010204030101041607010407 +0001040d0101040101010401010104010101040001010405010104000101040101010400 +010104010101040e070104e901170401010204180001040f010304020105040001010402 +010104010101040001050400010104100701040700010417010204020104040201020401 +01010416070104070001040d010104010101040101010401010104000101040201040400 +0101040101010400010104010101040e070104e901010403010204010101040201030400 +01020402010004190001040f010104000101040101010404010104020101040101010400 +010104040101041007010407000104180102040001010401010104030102040001010416 +070104070001040d01010401010104010101040201020402010104010101040001010401 +01010400010104010101040e070104e90101040201010400010104000102040001010400 +010104210001040f01010401010104000101040101010400010104020101040101010400 +010104010101040001010410070104070001041501010401010104000101040101010400 +010104010101040001010416070104070001040d01010401010104010101040201020402 +01010401010104000102040001010400010204000101040e070104e90101040201010400 +010104000102040001010400010104210001040f01010402010104000103040101010402 +010104010101040101030401010104100701040700010416010304020102040001010400 +0103040101010416070104070001040d0101040101010401010104030101040301020400 +0103040001010401010104000101040f070104e901030401010204010102040101030421 +000104430701040700010443070104070001041b0100040a0101040401010412070104ea +01020402010004030100040301000423000104430701040700010443070104070001041a +0101040a0101040401010412070104ff041f000104430701040700010443070104070001 +04190101040b0101040401010412070104ff041f00010443070104070001044307010407 +00010443070104ff041f0001044307010407000104430701040700010443070104ff041f +0000074604070000074604070000074604ff04200746040807460408074604ff04ff04ff +04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff042c01ff +01ff010704ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff +04ff04ff0447 +%%EndData +end +%%PageTrailer +%%Trailer +%%BoundingBox: 0 26 377 164 +%%EOF diff --git a/lib/appmon/doc/src/make.dep b/lib/appmon/doc/src/make.dep new file mode 100644 index 0000000000..ce0d7571a3 --- /dev/null +++ b/lib/appmon/doc/src/make.dep @@ -0,0 +1,26 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: appmon.tex appmon_chapter.tex book.tex part.tex \ + ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: app_win.ps listbox_win.ps main_win.ps pinfo_win.ps + diff --git a/lib/appmon/doc/src/note.gif b/lib/appmon/doc/src/note.gif Binary files differnew file mode 100644 index 0000000000..6fffe30419 --- /dev/null +++ b/lib/appmon/doc/src/note.gif diff --git a/lib/appmon/doc/src/notes.xml b/lib/appmon/doc/src/notes.xml new file mode 100644 index 0000000000..f624ce993b --- /dev/null +++ b/lib/appmon/doc/src/notes.xml @@ -0,0 +1,172 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Appmon Release Notes</title> + <prepared></prepared> + <docno>nil</docno> + <date>nil</date> + <rev>nil</rev> + <file>notes.xml</file> + </header> + <p>This document describes the changes made to the Appmon application.</p> + +<section><title>Appmon 2.1.10.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The documentation is now built with open source tools + (xsltproc and fop) that exists on most platforms. One + visible change is that the frames are removed.</p> + <p> + Own Id: OTP-8201</p> + </item> + </list> + </section> + +</section> + + <section> + <title>Appmon 2.1.10.1</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Updated the application with new tags for automatic updates + of copyright notices. + </p> + <p>Own Id: OTP-7851</p> + </item> + </list> + </section> + </section> + + <section> + <title>Appmon 2.1.9</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Fixed dialyzer warning in <c><![CDATA[appmon_info]]></c>.</p> + </item> + </list> + </section> + </section> + + <section> + <title>Appmon 2.1.8</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Removed some dead code from the <c><![CDATA[appmon_info]]></c> and + <c><![CDATA[process_info]]></c> modules. Also rewritten large parts + of <c><![CDATA[process_info]]></c> to make it easier to read and more + efficient.</p> + <p>Own Id: OTP-6534</p> + </item> + </list> + </section> + </section> + + <section> + <title>Appmon 2.1.7</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Appmon now handles a process name containing the + character '@' correctly. (Thanks to Mikael Magnusson).</p> + <p>Own Id: OTP-6308</p> + </item> + <item> + <p>The "Send" button in the application window was broken, + it always failed (silently).</p> + <p>Own Id: OTP-6333</p> + </item> + </list> + </section> + </section> + + <section> + <title>Appmon 2.1.6</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Internal change only (using a private digraph instead of + a public one).</p> + <p>Own Id: OTP-5983</p> + </item> + <item> + <p>Notification windows are now centered over the parent + window (if possible).</p> + <p>Own Id: OTP-6010 Aux Id: OTP-5987</p> + </item> + <item> + <p>Removed some dead code from <c><![CDATA[appmon_info]]></c>, + discovered by Dialyzer.</p> + <p>Own Id: OTP-6040</p> + </item> + </list> + </section> + </section> + + <section> + <title>Appmon 2.1.5</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Eliminated 5 discrepancies found by Dialyzer in the + Appmon application.</p> + <p>Own Id: OTP-5633</p> + </item> + </list> + </section> + </section> + + <section> + <title>Appmon 2.1.4</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The graphic applications now search for HTML + documentation in the correct place.</p> + <p>Own Id: OTP-5381</p> + </item> + </list> + </section> + </section> +</chapter> + diff --git a/lib/appmon/doc/src/part.xml b/lib/appmon/doc/src/part.xml new file mode 100644 index 0000000000..017957946c --- /dev/null +++ b/lib/appmon/doc/src/part.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Appmon User's Guide</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <description> + <p>The Application Monitor, <em>Appmon</em>, is a graphical utility used + to supervise applications executing either locally or on remote nodes. + The process tree of an application can furthermore be monitored.</p> + </description> + <xi:include href="appmon_chapter.xml"/> +</part> + diff --git a/lib/appmon/doc/src/part_notes.xml b/lib/appmon/doc/src/part_notes.xml new file mode 100644 index 0000000000..8b19d57d64 --- /dev/null +++ b/lib/appmon/doc/src/part_notes.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Appmon Release Notes</title> + <prepared>Ingela Anderton Andin</prepared> + <docno></docno> + <date>2004-09-07</date> + <rev></rev> + <file>part_notes.sgml</file> + </header> + <description> + <p>The Application Monitor, <em>Appmon</em>, is a graphical utility + used to supervise applications executing either locally or on + remote nodes. The process tree of an application can furthermore + be monitored.</p> + </description> + <include file="notes"></include> +</part> + diff --git a/lib/appmon/doc/src/pinfo_win.gif b/lib/appmon/doc/src/pinfo_win.gif Binary files differnew file mode 100644 index 0000000000..fda0900436 --- /dev/null +++ b/lib/appmon/doc/src/pinfo_win.gif diff --git a/lib/appmon/doc/src/pinfo_win.ps b/lib/appmon/doc/src/pinfo_win.ps new file mode 100644 index 0000000000..d47d7d47a9 --- /dev/null +++ b/lib/appmon/doc/src/pinfo_win.ps @@ -0,0 +1,1353 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: (ImageMagick) +%%Title: (./pinfo_win.tmp.eps) +%%CreationDate: (Tue Jun 12 18:01:56 2001) +%%BoundingBox: 0 73 377 347 +%%DocumentData: Clean7Bit +%%LanguageLevel: 1 +%%Pages: 0 +%%EndComments + +%%BeginDefaults +%%PageOrientation: Portrait +%%EndDefaults + +%%BeginProlog +% +% Display a color image. The image is displayed in color on +% Postscript viewers or printers that support color, otherwise +% it is displayed as grayscale. +% +/buffer 512 string def +/byte 1 string def +/color_packet 3 string def +/pixels 768 string def + +/DirectClassPacket +{ + % + % Get a DirectClass packet. + % + % Parameters: + % red. + % green. + % blue. + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/DirectClassImage +{ + % + % Display a DirectClass image. + % + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { DirectClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayDirectClassPacket } image + } ifelse +} bind def + +/GrayDirectClassPacket +{ + % + % Get a DirectClass packet; convert to grayscale. + % + % Parameters: + % red + % green + % blue + % length: number of pixels minus one of this color (optional). + % + currentfile color_packet readhexstring pop pop + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/GrayPseudoClassPacket +{ + % + % Get a PseudoClass packet; convert to grayscale. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + color_packet 0 get 0.299 mul + color_packet 1 get 0.587 mul add + color_packet 2 get 0.114 mul add + cvi + /gray_packet exch def + compression 0 gt + { + /number_pixels 1 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add def + } ifelse + 0 1 number_pixels 1 sub + { + pixels exch gray_packet put + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassPacket +{ + % + % Get a PseudoClass packet. + % + % Parameters: + % index: index into the colormap. + % length: number of pixels minus one of this color (optional). + % + currentfile byte readhexstring pop 0 get + /offset exch 3 mul def + /color_packet colormap offset 3 getinterval def + compression 0 gt + { + /number_pixels 3 def + } + { + currentfile byte readhexstring pop 0 get + /number_pixels exch 1 add 3 mul def + } ifelse + 0 3 number_pixels 1 sub + { + pixels exch color_packet putinterval + } for + pixels 0 number_pixels getinterval +} bind def + +/PseudoClassImage +{ + % + % Display a PseudoClass image. + % + % Parameters: + % class: 0-PseudoClass or 1-Grayscale. + % + currentfile buffer readline pop + token pop /class exch def pop + class 0 gt + { + currentfile buffer readline pop + token pop /depth exch def pop + /grays columns 8 add depth sub depth mul 8 idiv string def + columns rows depth + [ + columns 0 0 + rows neg 0 rows + ] + { currentfile grays readhexstring pop } image + } + { + % + % Parameters: + % colors: number of colors in the colormap. + % colormap: red, green, blue color packets. + % + currentfile buffer readline pop + token pop /colors exch def pop + /colors colors 3 mul def + /colormap colors string def + currentfile colormap readhexstring pop pop + systemdict /colorimage known + { + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { PseudoClassPacket } false 3 colorimage + } + { + % + % No colorimage operator; convert to grayscale. + % + columns rows 8 + [ + columns 0 0 + rows neg 0 rows + ] + { GrayPseudoClassPacket } image + } ifelse + } ifelse +} bind def + +/DisplayImage +{ + % + % Display a DirectClass or PseudoClass image. + % + % Parameters: + % x & y translation. + % x & y scale. + % label pointsize. + % image label. + % image columns & rows. + % class: 0-DirectClass or 1-PseudoClass. + % compression: 0-RunlengthEncodedCompression or 1-NoCompression. + % hex color packets. + % + gsave + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + x y translate + currentfile buffer readline pop + token pop /x exch def + token pop /y exch def pop + currentfile buffer readline pop + token pop /pointsize exch def pop + /Helvetica findfont pointsize scalefont setfont + x y scale + currentfile buffer readline pop + token pop /columns exch def + token pop /rows exch def pop + currentfile buffer readline pop + token pop /class exch def pop + currentfile buffer readline pop + token pop /compression exch def pop + class 0 gt { PseudoClassImage } { DirectClassImage } ifelse + grestore +} bind def +%%EndProlog +%%Page: 1 1 +%%PageBoundingBox: 0 73 377 347 +userdict begin +%%BeginData: +DisplayImage +0 73 +377.000000 274.000000 +12 +580 421 +1 +0 +0 +8 +ffffff +000000 +708090 +b03060 +d9d9d9 +c3c3c3 +828282 +000000 +03ff03ff03ff03ff03ff035e040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +04000300040003000400031a040c03c50400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +04000300040003000400030004000308040c03050400030a0400030a0401030304050301 +0405030104010304040103030403030304010302040103090405032d040103090402031e +040103010401031704000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +0400030004000307040003020400030204000302040003050400030a0400030904030302 +040103020401030004010302040103000401030404010302040103010401030204020301 +04010309040103020401032c04010308040103200401031a040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000308040003020400030204000302 +040003050400030304020303040003090400030104000302040103020401030004010302 +040103000402030204020301040103030401030104020301040103010401030504010302 +040303000401030004030302040303020403030204030302040303060401030004010300 +040103010403030104030301040103000402030004020300040203020403030104030300 +0401030104030301040103000401030a0400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003070400030204000302040003020400030504000302 +040403020400030804010301040103010401030204010300040103020401030004020302 +040203010401030304010301040103000400030004010301040103050401030204080301 +040103000401030104010300040103010401030004010301040103000401030104010305 +040103000402030004010301040103010401030104010300040603010401030104010300 +040103010401030104010301040103000401030104010300040203000401030804000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030804040302 +040003020400030504000301040603010400030804010301040103010405030104050301 +040303000403030104010303040103010401030004000300040103090405030004020301 +040103010401030004010304040103010401030004020303040203080401030004010301 +040103010401030104010301040103000402030104010301040103010401030404010301 +040103010401030004010301040103000401030104010309040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000307040003060400030204000305 +040003010406030104000308040503010401030504010305040103000400030004000300 +040103010401030304010301040103010402030904010304040103020401030104010300 +040103040405030204020303040203060401030004010301040103010401030104010301 +040103000401030204010301040103010401030104040301040103010401030004010301 +040103000401030104010308040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000308040003060400030204000305040003010406030104000307 +040103030401030004010305040103050401030004020300040103010401030304010301 +040103010402030904010304040103020401030104010300040103040401030704020303 +040203050401030004010301040103010401030104010301040103000401030204010301 +040103010401030004010301040103010401030104010300040103010401030004010301 +040103090400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003070400030604000302040003050400030204040302040003070401030304010300 +040103050401030504010301040003010401030204010301040103020401030204010301 +040103050401030404010302040103010401030004010301040103000401030104010300 +040103010401030004010301040103050401030004010301040103010401030104010301 +040103000401030204010301040103010401030004010301040103010401030004020300 +040103010401030004010301040103080400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003080408030204000305040003030402030304000307 +040103030401030004010305040103050401030104000301040103030403030304010302 +040103010401030504010304040103030403030204030302040303020403030204030306 +040103000401030104010301040103020403030104010302040103010401030104010301 +040203000401030104010300040103010403030104010301040103090400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003070400030a04000305 +0400030a040003c504000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +04000300040003080400030a040003050400030a040003c6040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +0400030004000300040003000400030004000300040003070400030a04000305040c03c5 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000308 +040c03d90400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003000400030004000300040003000400030004000300040003000400030004000300 +040003ff03ff03ff03ff039f02ff02ff02ff02ff028700ff00ff00ff00ff008606000001 +04ff04ff043f0601000104ff04ff043f0601000104ff04ff043f0601000104ff04ff043f +0601000104ff04ff043f0601000104040104040401000403010204ff04ff042806010001 +04040100040f010004ff04ff0428060100010404010004060102040501000403010204ff +04ff042106010001040401000408010004050100040201000402010004ff04ff04200601 +0001040401030405010004050100040201000402010004ff04ff04200601000104040100 +04080100040501000402010404ff04ff0420060100010404010004080100040501000402 +010004ff04ff042406010001040401000408010004050100040201000402010004ff04ff +0420060100010404010004080100040501000403010204ff04ff04210601000104ff04ff +043f0601000104ff04ff043f0601000104ff04ff043f0601000104ff04ff043f06010001 +04ff04ff043f0601000104ff04ff043f0601000106ff06ff0641000006ff06ff064204ff +04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff0484061204ff04ff04300611 +0000040106ff06ff062c040106010506060005060001040106ff06ff062b000004010601 +0505000006000506000104010601040a0101045f0101047801010404010104ff04370001 +0401060105050000060105050001040106010409010004600100047c01000405010004ff +043600010401060105040001060105050001040106010409010004060100040c01000404 +010004060100040a01020418010204030102040b0100042701020405010004020100040f +0100040c01000404010004180104040301000405010004ff043600010401060105040001 +04000601050400010401060104090100041a010004140100041a010004050100040b0100 +04290100040901000423010004180100040701000405010004ff04360001040106010503 +000104010601050400010401060104090100040401020402010004000101040301020402 +0104040201020403010204050100040a0102040301020405010004050100040b01000403 +01000400010104020100040001010403010204030102040c010004030102040201000400 +0101040a0102040201000400010104030102040201040408010004000101040901000407 +01000405010004ff04360001040106010503000104020601050300010401060104090100 +040601000402010104010100040401000404010004060100040201000402010004040100 +040901000402010004010100040201000404010004050100040b01000403010104010100 +040101010401010004010100040201000401010004020100040b01000405010004020101 +04010100040b010004020101040101000404010004040100040a01010401010004080103 +040401000405010004ff0436000104010601050200010403060105030001040106010407 +010104070100040201000402010004040100040401000406010004060100040401000409 +010004090100040401000405010004090101040401000402010004010100040501000402 +010004010100040f0100040501000402010004020100040b010004020100040201000404 +010004040100040a010004020100040c0100040401010404010104ff0434000104010601 +050200010404060105020001040106010409010004060100040201000402010004040100 +0404010004060100040301030404010004090100040601030404010004050100040b0100 +040301000402010004010100040501000402010004010100040f01000405010004020100 +04020100040b010004020100040201000404010004040100040a010004020100040c0100 +040301000405010004ff0436000104010601050100010405060105020001040106010409 +010004060100040201000402010004040100040401000406010004020100040201000404 +01000409010004050100040201000404010004050100040b010004030100040201000401 +0100040501000402010004010100040f0100040501000402010004020100040b01000402 +0100040201000404010004040100040a0100040201000408010004020100040301000405 +010004ff0436000104010601050100010406060105010001040106010409010004060100 +040201000402010004040100040401000406010004020100040201000404010004090100 +040201000401010004020100040401000405010004040101040401000403010104010100 +0401010004050100040201000401010004020100040b0100040501000402010104010100 +040301010405010004020100040201000404010004040100040a01010401010004030101 +040201000402010004030100040501000405010104ff042e000104010601050000010407 +060105010001040106010409010004060100040201000402010004040100040501010404 +01000403010304040100040a010204030103040401000405010004040101040401000403 +010004000101040201000406010204030102040c01000405010004020100040001010404 +010104050100040201000402010004040100040501010408010004000101040401010403 +010204040100040501000405010104ff042e000104010601050000010408060105000001 +0401060104090100043301050420010004040100040301000419010504190100041d0105 +0401010004080100040b0100040501000406010004ff042e0001040106010001060b0500 +000104010601040a0101045601010406010104010100043701010426010004060101040a +0101040401010405010104ff042f0001040106010000060d000104010601047001000460 +010004ff0454000104010601050e000104010601040a01010463010104ff04b500010401 +0601050e000104010601040901000467010004ff04b4000104010601050e000104010601 +04090100040c0100040c01000429010004040100040601000412010004ff04b400010401 +0601050e00010401060104090100040c0100040c0100042f0100041a010004ff04b40001 +04010601050e000104010601040901000404010204020104040201020402010404010100 +040201000402010204090100040201000402010204030102040201040402010204020100 +0400010104030101040001000403010004ff04b4000104010601050e0001040106010409 +010004030100040201000403010004030100040201000403010004030100040201000401 +010004020100040801000402010004010100040201000404010004040100040601000402 +01010401010004010100040101010403010004ff04b4000104010601050e000104010601 +0407010104040100040701000407010004030100040301000402010004010100040c0100 +040001000400010004050100040401000404010004060100040201000402010004010100 +040201000404010104ff04b2000104010601050e00010401060104090100040401020404 +010004040103040301000403010004020100040201020409010004000100040001000402 +0103040401000404010004060100040201000402010004010100040201000403010004ff +04b4000104010601050e0001040106010409010004070100040301000403010004020100 +040301000403010004020100040501000408010004000100040001000401010004020100 +040401000404010004060100040201000402010004010100040201000403010004ff04b4 +000104010601050e00010401060104090100040301000402010004030100040301000402 +010004030100040301000401010104010100040201000403010104020100040001000400 +010004010100040201000404010004040100040601000402010004020100040101000401 +0101040301000405010104ff04ac000104010601050e0001040106010409010004040102 +040501010402010304040101040201010400010004020102040401010403010004000100 +040301030404010004050101040401000402010004020100040201010400010004030100 +0405010104ff04ac000104010601050e0001040106010409010004300100043001000403 +01000406010004ff04ac000104010601050e000104010601040a0101042c0101042d0100 +04020100040101010405010104ff04ad000104010601050e000104010601046a010204ff +04ba000104010601050e000104010601040a01010486010104ff0492000104010601050e +00010401060104090100048a010004ff0491000104010601050e00010401060104090100 +04660102041901010404010004ff0491000104010601050e000104010601040901000468 +010004180100040101000403010004ff0491000104010601050e00010401060104090100 +040301010400010004030102040301020403010204030102040301010400010004020102 +040a010104000100040101000402010004020102040201000402010004020102040c0100 +040301020402010004000101040a0100040101000403010004ff0491000104010601050e +000104010601040901000403010004000100040001000401010004020100040101000402 +010004010100040201000401010004020100040101000401010104010100040201000408 +010004010101040101000402010004010100040201000401010004020100040101000402 +0100040b01000402010004020100040101010401010004090100040101000403010004ff +0491000104010601050e0001040106010407010104040100040001000400010004010100 +040201000401010004050100040901000401010004020100040101000402010004080100 +040201000401010004020100040101000402010004010100040201000401010004020100 +040b01000402010004020100040101000402010004090100040101000404010104ff048f +000104010601050e00010401060104090100040301000400010004000100040101040402 +010204030102040301030401010004020100040101040408010004020100040101000402 +010004010104040101000402010004010104040b01000402010404010100040201000409 +0100040101000403010004ff0491000104010601050e0001040106010409010004030100 +040001000400010004010100040901000405010004010100040201000401010004020100 +04010100040c010004020100040101000402010004010100040501000402010004010100 +040f010004020100040501000402010004090100040101000403010004ff049100010401 +0601050e0001040106010409010004030100040001000400010004010100040201000401 +010004020100040101000402010004010100040201000401010004010101040101000402 +010004080100040101010401010004010101040101000402010004010100040101010401 +010004020100040b01000402010004020100040101000402010004030101040301000401 +0100040301000405010104ff0489000104010601050e0001040106010409010004030100 +040001000400010004020102040301020403010204030103040201010400010004020102 +040a010104000100040201010400010004020102040301010400010004020102040c0100 +0403010204020100040201000403010104040101040401000405010104ff048900010401 +0601050e00010401060104090100042a01000407010504050100041c010504190100040b +01000406010004ff0489000104010601050e000104010601040a01010424010004020100 +04130100043a0101040a01010405010104ff048a000104010601050e0001040106010432 +01020414010004ff04dc000104010601050e000104010601040a0101044e010104ff04ca +000104010601050e0001040106010409010004430103040101030404010004ff04c90001 +04010601050e0001040106010409010004430100040701000404010004ff04c900010401 +0601050e0001040106010409010004430100040701000404010004ff04c9000104010601 +050e00010401060104090100040301010400010004030102040301020403010204030102 +04030101040001000402010204030102040a0100040701000404010004ff04c900010401 +0601050e0001040106010409010004030100040001000400010004010100040201000401 +010004020100040101000402010004010100040201000401010004010101040101000402 +0100040101000402010004090100040701000404010004ff04c9000104010601050e0001 +040106010407010104040100040001000400010004010100040201000401010004050100 +040901000401010004020100040101000402010004010100040d01000407010004050101 +04ff04c70001040106010010040106010409010004030100040001000400010004010104 +04020102040301020403010304010100040201000401010404020102040a010004070100 +0404010004ff04c9000104010601000d0600000104010601040901000403010004000100 +040001000401010004090100040501000401010004020100040101000402010004010100 +0409010004090100040701000404010004ff04c90001040106010001040a060100010401 +060104090100040301000400010004000100040101000402010004010100040201000401 +010004020100040101000402010004010100040101010401010004020100040101000402 +0100040301010403010004070100040401000405010104ff04c10001040106010001040a +060100010401060104090100040301000400010004000100040201020403010204030102 +040301030402010104000100040201020403010204040101040301000407010004040100 +0405010104ff04c10001040106010001040a060100010401060104090100042a01000412 +01000403010304010103040401000406010004ff04c10001040106010001040a06010001 +04010601040a0101042401000402010004100101041101010405010104ff04c200010401 +06010001040a06010001040106010432010204ff04f20001040106010001040a06010001 +04010601040a01010478010104ff04a00001040106010001040a06010001040106010409 +0100042e01030405010004310100040601030404010004ff049f0001040106010001040a +060100010401060104090100040401020405010004090100041401000407010004040101 +040b01000405010104030102040b010104020100040801000404010004ff049f00010401 +06010001040a060100010401060104090100040601000410010004140100040601000404 +010004010100040901010404010004010100040101000402010004090100040101000402 +0100040701000404010004ff049f0001040106010001040a060100010401060104090100 +04060100040301020402010004000101040201000401010004030102040a010004050100 +040501000401010004080100040001000404010004010100040501000409010004010100 +04030100040601000404010004ff049f0001040106010001040a06010001040106010409 +010004060100040501000402010104010100040101000400010004030100040201000409 +0100040401000406010004010100040a0100040401000401010004050100040901000401 +010004040100040501000404010004ff049f0001040106010001040a0601000104010601 +04070101040701000405010004020100040201000401010104040100040d010004030100 +0407010004010100040a0100040401000401010004030101040a01000401010004050100 +040401000405010104ff049d0001040106010001040a0601000104010601040901000406 +01000405010004020100040201000401010104050102040a010004040100040601000401 +0100040a0100040401000401010004050100040901000401010004040100040501000404 +010004ff049f0001040106010001040a0601000104010601040901000406010004050100 +040201000402010004010100040001000407010004090100040501000405010004010100 +040a01000404010004010100040501000409010004010100040301000406010004040100 +04ff049f0001040106010001040a06010001040106010409010004060100040501000402 +010004020100040101000401010004020100040201000403010104030100040601000404 +010004010100040301010404010004040100040101000401010004020100040301010403 +0100040101000402010004070100040401000405010104ff04970001040106010001040a +060100010401060104090100040601000405010004020100040201000401010004020100 +040201020404010104030100040701000404010104040101040201040403010104030102 +04040101040401010402010004080100040401000405010104ff04970001040106010001 +040a06010001040106010409010004290100040301030405010004310100040601030404 +01000406010004ff04970001040106010001040a0601000104010601040a010104250101 +045001010405010104ff04980001040106010001040a060100010401060104ff04ff0428 +0001040106010001040a0601000104010601040a01010458010104ff0419010104a40001 +040106010001040a06010001040106010409010004510103040301000406010004040100 +04450100040a01030475010004310100040601030404010004a30001040106010001040a +0601000104010601040901000407010004040100040b010004060100042d010004060100 +040601000403010204270100041b0100040a01000477010004040101040b010004050101 +04040100040c010104020100040801000404010004a30001040106010001040a06010001 +040106010409010004070100041101000435010004060100040501000403010004000100 +0400010004260100041a0100040b01000476010004040100040101000409010104040100 +0401010004020101040b01000401010004020100040701000404010004a3000104010601 +0001040a0601000104010601040901000404010104000100040201020403010204020104 +040201020403010204020100040001010403010204020100040001010402010004020100 +040901000406010004040100040401000400010004040102040201000400010104030102 +0403010204030102040201040402010204020100040001010403010204030100040c0100 +040401010400010004020100040201000402010204020100040201000401010004000101 +040901010400010004020100040201000402010204020100040001010402010004000101 +040a010204020100040201000401010004000101040a0100040501000401010004080100 +0400010004040100040101000401010004000100040b0100040101000403010004060100 +0404010004a30001040106010001040a0601000104010601040901000403010004010101 +040401000402010004020100040301000406010004020100040201000401010104010100 +0401010004020100040101010401010004010100040201000409010004060100040a0100 +040001000403010004020100040101010401010004010100040201000401010004020100 +040101000402010004030100040301000402010004010101040101000401010004020100 +041001000404010004000100040001000401010004020100040101000402010004010100 +040201000401010104010100040801000400010004000100040101000402010004010100 +040201000401010104010100040101010401010004080100040201000401010004020100 +0401010104010100040801000406010004010100040a0100040401000401010004030100 +040b01000401010004040100040501000404010004a30001040106010001040a06010001 +040106010407010104040100040201000404010004020100040701000406010004020100 +040201000401010004020100040501000401010004060100040101000409010004040101 +040c01020406010004010100040201000401010004050100040201000401010004070100 +040301000402010004010100040501000414010004040100040001000400010004020100 +040101000401010004050100040201000401010004020100040801000400010004000100 +040201000401010004050100040101000402010004010100040201000408010004050100 +040201000401010004020100040701000407010004010100040a01000404010004010100 +04030100040b01000401010004050100040401000405010104a10001040106010001040a +060100010401060104090100040301000402010004040100040201000407010004060100 +040201000402010004010100040201000402010304010100040601000401010004090100 +04060100040c010004000100040201030401010004020100040101000405010404020102 +040401000403010004020100040101000406010204110100040401000400010004000100 +040201000401010004020102040201000402010004010100040201000408010004000100 +040001000402010004010100040201030401010004020100040101000402010004090102 +04020100040201000401010004020100040801000406010004010100040a010004040100 +0401010004030100040b01000401010004040100040501000404010004a3000104010601 +0001040a0601000104010601040901000403010004020100040401000402010004070100 +040601000402010004020100040101000402010004010100040201000401010004070100 +040001000409010004060100040c01000400010004010100040201000401010004020100 +040101000405010004090100040301000403010004020100040101000409010004100100 +040401000400010004000100040301000400010004050100040101000402010004010100 +040201000408010004000100040001000403010004000100040101000402010004010100 +040201000401010004020100040c01000401010004020100040101000402010004090100 +0405010004010100040a0100040401000401010004030100040b01000401010004030100 +040601000404010004a30001040106010001040a06010001040106010409010004030100 +040101010404010004020100040201000403010004060100040201000402010004010100 +0402010004010100040201000401010004070101040401010403010004060100040a0100 +040001000400010004010100040201000401010004020100040101000402010004010100 +040201000401010004020100040301000403010004020100040101000405010004020100 +040a01010403010004040100040001000400010004030101040201000402010004010100 +040101010401010104010100040301010402010004000100040001000403010104020100 +040201000401010104010100040101010401010004080100040201000401010004010101 +040101010401010004030101040401000404010004010100040301010404010004040100 +040101000403010004050101040301000401010004020100040701000404010004050101 +049b0001040106010001040a060100010401060104090100040401010400010004040100 +040301020405010104040100040301020402010004020100040201030401010004080100 +040401010403010004060100040b01020403010304010100040201000402010204030102 +0403010204050101040201020402010004060102040b0101040301000404010004000100 +040001000404010004030102040301010400010004010100040001010404010104020100 +0400010004000100040401000403010304010100040001010402010004000101040a0102 +040301010400010004010100040001010404010104050100040401010404010104020104 +0403010104020104040301010404010104020100040801000404010004050101049b0001 +040106010001040a06010001040106010409010004450100040501000403010304030100 +040c0100044c010004030103040b01000410010004080100040c01000409010004050100 +04040105040f0100040801000406010004310100040601030404010004060100049b0001 +040106010001040a0601000104010601040a0101044001000400010004040101040d0101 +0456010104110100040001000411010004060101040a010004000100040a010004050100 +041a0100040601010449010104050101049c0001040106010001040a0601000104010601 +044e0100048301000412010004140100040b010004050100041a010004f9000104010601 +0001040a0601000104010601046501010474010104ff04490001040106010001040a0601 +000104010601046401000406010004040100045a0100040b010004ff044b000104010601 +0001040a060100010401060104640100040601000403010204050100040c010004040100 +04060100040a0102041801020403010204050100040b010004220100040c010004040100 +040d01000404010004fe0001040106010001040a06010001040106010464010004050100 +0403010004000100040001000418010004140100041a01000405010004040100040c0100 +043601000413010004fe0001040106010001040a06010001040106010464010004040100 +040401000400010004040102040201000400010104030102040201040402010204030102 +04050100040a010204030102040501000405010004030100040d01000404010104000100 +040201020402010004000101040a01020402010004000101040301020402010404090102 +0402010404fc0001040106010001040a060100010401060104640100040a010004000100 +040601000402010104010100040401000404010004060100040201000402010004040100 +040901000402010004010100040201000404010004050100041201000403010004010101 +04010100040201000401010104010100040b010004020101040101000404010004040100 +040d01000404010004fe0001040106010001040a060100010401060104620101040c0102 +040501000402010004020100040401000404010004060100040601000404010004090100 +040901000404010004050100041001010404010004020100040101000402010004010100 +04020100040b010004020100040201000404010004040100040d01000404010004fe0001 +040106010001040a060100010401060104640100040c0100040001000404010004020100 +040201000404010004040100040601000403010304040100040901000406010304040100 +04050100041201000403010004020100040101040401010004020100040b010004020100 +040201000404010004040100040d01000404010004fe0001040106010001040a06010001 +0401060104640100040c0100040001000404010004020100040201000404010004040100 +040601000402010004020100040401000409010004050100040201000404010004050100 +041201000403010004020100040101000405010004020100040b01000402010004020100 +0404010004040100040d01000404010004fe0001040106010001040a0601000104010601 +04640100040a010004000100040001000404010004020100040201000404010004040100 +040601000402010004020100040401000409010004020100040101000402010004040100 +04050100040b010104040100040301000401010104010100040201000401010004020100 +040301010405010004020100040201000404010004040100040d01000404010004050101 +04f60001040106010001040a060100010401060104640100040b01020405010004020100 +040201000404010004050101040401000403010304040100040a01020403010304040100 +04050100040b010104040100040401010400010004020102040201000402010004030101 +0405010004020100040201000404010004050101040b0100040501010403010104f60001 +040106010001040a060100010401060104640100040c0100043301050427010004040100 +0407010004120100041d01050412010004f60001040106010001040a0601000104010601 +04650101046b0101040601010401010004020100041001010435010104f7000104010601 +0001040a060100010401060104e1010204ff04430001040106010001040a060100010401 +060104ff04ff04280001040106010001040a060100010401060104fd010304ff04260001 +040106010001040a060100010401060104fd010004ff04290001040106010001040a0601 +00010401060104fd010004ff04290001040106010001040a060100010401060104fd0100 +0405010104000100040201020402010004000101040a0102040301020402010004000101 +040201000402010004020102040201000400010104e10001040106010001040a06010001 +0401060104fd010004040100040101010401010004020100040101010401010004080100 +040201000401010004020100040101010401010004010100040201000401010004020100 +040101010401010004e00001040106010001040a060100010401060104fd010004040100 +040201000401010004020100040101000402010004080100040501000402010004010100 +040501000402010004010100040201000401010004e40001040106010001040a06010001 +0401060104fd010004040100040201000401010404010100040201000409010204020104 +040101000406010004000100040201040401010004e40001040106010001040a06010001 +0401060104fd01000404010004020100040101000405010004020100040c010004010100 +040501000406010004000100040201000405010004e40001040106010001040a06010001 +0401060104fd010004040100040101010401010004020100040101000402010004080100 +040201000401010004020100040101000407010004030100040201000401010004070101 +04da0001040106010001040a060100010401060104fd0100040501010400010004020102 +040201000402010004090102040301020402010004070100040401020402010004070101 +04da0001040106010001040a060100010401060104fd010304050100040e0105042e0100 +04da0001040106010001040a060100010401060104ff04030100040201000441010104db +0001040106010001040a060100010401060104ff0404010204ff04200001040106010001 +040a060100010401060104ff04ff04280001040106010001040a060100010401060104ff +040701000431010004ec0001040106010001040a060100010401060104ff040601000404 +0101040b01000405010104030102040b01010402010004eb0001040106010001040a0601 +00010401060104ff04050100040401000401010004090101040401000401010004010100 +0402010004090100040101000402010004ea0001040106010001040a0601000104010601 +04ff04040100040501000401010004080100040001000404010004010100040501000409 +0100040101000403010004e90001040106010001040a060100010401060104ff04030100 +0406010004010100040a0100040401000401010004050100040901000401010004040100 +04e80001040106010001040a060100010401060104ff040201000407010004010100040a +0100040401000401010004030101040a0100040101000405010004e70001040106010001 +040a060100010401060104ff040301000406010004010100040a01000404010004010100 +0405010004090100040101000404010004e80001040106010001040a0601000104010601 +04ff040401000405010004010100040a0100040401000401010004050100040901000401 +01000403010004e90001040106010001040a060100010401060104ff0405010004040100 +040101000403010104040100040401000401010004010100040201000403010104030100 +04010100040201000406010104e10001040106010001040a060100010401060104ff0406 +010004040101040401010402010404030101040301020404010104040101040201000407 +010104e10001040106010001040a060100010401060104ff040701000431010004090100 +04e10001040106010001040a060100010401060104ff0443010104e20001040106010001 +040a060100010401060104ff04ff04280001040106010001040a060100010401060104ff +04ff04280001040106010001040a060100010401060104ff040701000431010004ec0001 +040106010001040a060100010401060104ff0406010004040101040b0100040501010403 +0102040b01010402010004eb0001040106010001040a060100010401060104ff04050100 +040401000401010004090101040401000401010004010100040201000409010004010100 +0402010004ea0001040106010001040a060100010401060104ff04040100040501000401 +0100040801000400010004040100040101000405010004090100040101000403010004e9 +0001040106010001040a060100010401060104ff040301000406010004010100040a0100 +04040100040101000405010004090100040101000404010004e80001040106010001040a +060100010401060104ff040201000407010004010100040a010004040100040101000403 +0101040a0100040101000405010004e70001040106010001040a060100010401060104ff +040301000406010004010100040a01000404010004010100040501000409010004010100 +0404010004e80001040106010001040a060100010401060104ff04040100040501000401 +0100040a010004040100040101000405010004090100040101000403010004e900010401 +06010001040a060100010401060104ff0405010004040100040101000403010104040100 +040401000401010004010100040201000403010104030100040101000402010004060101 +04e10001040106010001040a060100010401060104ff0406010004040101040401010402 +010404030101040301020404010104040101040201000407010104e10001040106010001 +040a060100010401060104ff04070100043101000409010004e10001040106010001040a +060100010401060104ff0443010104e20001040106010001040a060100010401060104ff +04ff04280001040106010001040a060100010401060104ff040601010463010104b90001 +040106010001040a060100010401060104ff040501000467010004b80001040106010001 +040a060100010401060104ff0405010004040102041801020443010004b8000104010601 +0001040a060100010401060104ff0405010004060100041a01000443010004b800010401 +06010001040a060100010401060104ff0405010004060100040301020403010204030102 +040501000409010104000100040201000402010004020102040301020402010004000101 +04020100040201000402010204020100040001010404010004b80001040106010001040a +060100010401060104ff0405010004060100040201000402010004010100040201000401 +010004020100040401000409010004000100040001000401010004020100040101000402 +010004010100040201000401010104010100040101000402010004010100040201000401 +0101040101000403010004b80001040106010001040a060100010401060104ff04030101 +040701000402010004020100040101000409010004040100040901000400010004000100 +040201000401010004010100040501000402010004010100040501000402010004010100 +04020100040101000408010104b60001040106010001040a060100010401060104ff0405 +010004060100040201000402010004010100040601030404010004090100040001000400 +010004020100040101000402010204020104040101000406010004000100040201040401 +01000407010004b80001040106010001040a060100010401060104ff0405010004060100 +040201000402010004010100040501000402010004040100040901000400010004000100 +040301000400010004050100040101000405010004060100040001000402010004050100 +0407010004b80001040106010001040a060100010401060104ff04050100040601000402 +010004020100040101000402010004010100040201000404010004040101040201000400 +010004000100040301010402010004020100040101000402010004010100040701000403 +01000402010004010100040701000405010104b00001040106010001040a060100010401 +060104ff0405010004060100040301020403010204030103040401000404010104020100 +040001000400010004040100040301020403010204020100040701000404010204020100 +040701000405010104b00001040106010001040a060100010401060104ff040501000429 +0100040c0100042e01000406010004b00001040106010001040a060100010401060104ff +0406010104250101040a010004000100042d01010405010104b10001040106010001040a +060100010401060104ff043c010004ea0001040106010001040a060100010401060104ff +04ff04280001040106010001040a060100010401060104ff04ff04280001040106010001 +040a060100010401060104ff04ff04280001040106010001040a060100010401060104ff +04ff04280001040106010001040a060100010401060104ff040301010400010004020100 +040201000402010204030102040201000400010104020100040201000402010204020100 +0400010104ef0001040106010001040a060100010401060104ff04030100040001000400 +010004010100040201000401010004020100040101000402010004010101040101000401 +0100040201000401010004020100040101010401010004ee0001040106010001040a0601 +00010401060104ff04030100040001000400010004020100040101000401010004050100 +0402010004010100040501000402010004010100040201000401010004f2000104010601 +0001040a060100010401060104ff04030100040001000400010004020100040101000402 +010204020104040101000406010004000100040201040401010004f20001040106010001 +040a060100010401060104ff040301000400010004000100040301000400010004050100 +04010100040501000406010004000100040201000405010004f20001040106010001040a +060100010401060104ff0403010004000100040001000403010104020100040201000401 +01000402010004010100040701000403010004020100040101000407010104e800010401 +06010001040a060100010401060104ff0403010004000100040001000404010004030102 +04030102040201000407010004040102040201000407010104e80001040106010001040a +060100010401060104ff040d0100042f010004e80001040106010001040a060100010401 +060104ff040a010004000100042e010104e90001040106010001040a0601000104010601 +04ff040b010004ff041b0001040106010001040a060100010401060104ff04ff04280001 +040106010001040a060100010401060104ff040401030401010304ff0419000104010601 +0001040a060100010401060104ff040401000407010004ff04190001040106010001040a +060100010401060104ff040401000407010004ff04190001040106010001040a06010001 +0401060104ff040401000407010004ff04190001040106010001040a0601000104010601 +04ff040401000407010004ff04190001040106010001040a060100010401060104ff0404 +01000407010004ff04190001040106010001040a060100010401060104ff040401000407 +010004ff04190001040106010001040a060100010401060104ff040401000407010004ff +04190001040106010001040a060100010401060104ff04040100040701000404010104ff +04120001040106010001040a060100010401060104ff04040100040701000404010104ff +04120001040106010001040a060100010401060104ff04040103040101030405010004ff +04120001040106010001040a060100010401060104ff0412010104ff0413000104010601 +0001040a060100010401060104ff04ff04280001040106010001040a0601000104010601 +04ff0418010104040101040b010104f80001040106010001040a060100010401060104ff +0404010304010103040201030404010004050100040301030404010004f7000104010601 +0001040a060100010401060104ff04040100040701000405010004040100040501000406 +01000404010004f70001040106010001040a060100010401060104ff0404010004070100 +040501000404010004050100040601000404010004f70001040106010001040a06010001 +0401060104ff0404010004070100040501000404010004050100040601000404010004f7 +0001040106010001040a060100010401060104ff04040100040701000405010004040100 +04050100040601000404010004f70001040106010001040a060100010401060104ff0404 +010004070100040501000405010104040101040401000405010104f50001040106010001 +040a060100010401060104ff040401000407010004050100040401000405010004060100 +0404010004f70001040106010001040a060100010401060104ff04040100040701000405 +01000404010004050100040601000404010004f70001040106010001040a060100010401 +060104ff0404010004070100040501000404010004050100040601000404010004050101 +04ef0001040106010001040a060100010401060104ff0404010004070100040501000404 +01000405010004060100040401000405010104ef0001040106010001040a060100010401 +060104ff0404010304010103040201030404010004050100040301030404010004060100 +04ef0001040106010001040a060100010401060104ff0418010104040101040b01010405 +010104f00001040106010001040a060100010401060104ff04ff04280001040106010001 +040a0601000104010601040a0101046a010104ff04ae0001040106010001040a06010001 +0401060104090100046e010004ff04ad0001040106010001040a06010001040106010409 +0100040501000430010004040100040d0101040901020412010004ff04ad000104010601 +0001040a0601000104010601040901000405010004360100040c0100040d010004120100 +04ff04ad0001040106010001040a06010001040106010409010004030104040101000400 +0101040301020402010004000101040a010204020100040201000402010204020104040a +0100040401020405010004030102040301020404010004ff04ad0001040106010001040a +060100010401060104090100040501000403010104010100040101000402010004010101 +04010100040801000402010004010100040201000404010004040100040a010404010100 +0402010004040100040201000402010004010100040201000403010004ff04ad00010401 +06010001040a060100010401060104070101040601000403010004090100040101000402 +0100040801000402010004020100040001000405010004040100040c0100040701000404 +01000402010004050100040201000404010104ff04ab0001040106010001040a06010001 +040106010409010004050100040301000406010304010100040201000408010404030100 +0406010004040100040c0100040401030404010004030102040201040403010004ff04ad +0001040106010001040a0601000104010601040901000405010004030100040501000402 +010004010100040201000408010004060100040001000405010004040100040c01000403 +0100040201000404010004060100040101000407010004ff04ad0001040106010001040a +060100010401060104090100040501000403010004050100040201000401010104010100 +040801000402010004010100040201000404010004040100040501010404010004030100 +040201000404010004020100040201000401010004020100040301000405010104ff04a5 +0001040106010001040a0601000104010601040901000406010104010100040601030401 +010004000101040a01020402010004020100040401000405010104030101040401000404 +0103040401000403010204030102040401000405010104ff04a50001040106010001040a +060100010401060104090100041801000404010504200100042701000406010004ff04a5 +0001040106010001040a0601000104010601040a01010416010004290101042601010405 +010104ff04a60001040106010001040a06010001040106010423010004ff04ff04030001 +040106010001040a0601000104010601040a010104be010104ff045a0001040106010001 +040a06010001040106010409010004c2010004ff04590001040106010001040a06010001 +0401060104090100042d0100041701000402010204410100041701000402010204120100 +04ff04590001040106010001040a060100010401060104090100042d0100041701000404 +01000441010004170100040401000412010004ff04590001040106010001040a06010001 +040106010409010004040102040201000400010104020100040001010403010204020100 +040001010409010004000101040301020402010004000101040301010400010004040100 +040301020402010004000101040a01020402010004000101040201000400010104030102 +040201000400010104090100040001010403010204020100040001010403010104000100 +040401000403010204020100040001010404010004ff04590001040106010001040a0601 +000104010601040901000403010004020100040101010401010004010101040101000401 +010004020100040101010401010004080101040101000401010004020100040101010401 +010004010100040101010404010004020100040201000401010104010100040801000402 +010004010101040101000401010104010100040101000402010004010101040101000408 +010104010100040101000402010004010101040101000401010004010101040401000402 +01000402010004010101040101000403010004ff04590001040106010001040a06010001 +040106010407010104040100040201000401010004050100040501000402010004010100 +040c01000402010004050100040101000402010004010100040201000404010004020100 +0402010004010100040c0100040201000401010004050100040501000402010004010100 +040c01000402010004050100040101000402010004010100040201000404010004020100 +04020100040101000408010104ff04570001040106010001040a06010001040106010409 +0100040301040401010004050100040501000402010004010100040c0100040201000402 +010304010100040201000401010004020100040401000402010404010100040c01040401 +010004050100040501000402010004010100040c01000402010004020103040101000402 +010004010100040201000404010004020104040101000407010004ff0459000104010601 +0001040a0601000104010601040901000403010004050100040501000405010004020100 +04010100040c010004020100040101000402010004010100040201000401010004020100 +040401000402010004050100040c01000405010004050100040501000402010004010100 +040c01000402010004010100040201000401010004020100040101000402010004040100 +04020100040501000407010004ff04590001040106010001040a06010001040106010409 +010004030100040201000401010004050100040501000402010004010100040c01000402 +010004010100040201000401010004020100040101000401010104040100040201000402 +010004010100040701010402010004020100040101000405010004050100040201000401 +0100040c0100040201000401010004020100040101000402010004010100040101010404 +0100040201000402010004010100040701000405010104ff04510001040106010001040a +0601000104010601040901000404010204020100040501000406010204020100040c0100 +040201000402010304010100040201000402010104000100040401000403010204020100 +040701010403010204020100040501000406010204020100040c01000402010004020103 +040101000402010004020101040001000404010004030102040201000407010004050101 +04ff04510001040106010001040a06010001040106010409010004250105043501000424 +0105043401000406010004ff04510001040106010001040a0601000104010601040a0101 +045d0101045e01010405010104ff04520001040106010001040a060100010401060104ff +04ff04280001040106010001040a0601000104010601040a0101046a010104ff04ae0001 +040106010001040a060100010401060104090100046e010004ff04ad0001040106010001 +040a060100010401060104090100041401000413010004040100043501020404010004ff +04ad0001040106010001040a060100010401060104090100042f01000437010004040100 +04ff04ad0001040106010001040a06010001040106010409010004030100040001010402 +010004000101040301020403010204020100040001010403010204020104040101000402 +010004080100040001010403010204020100040001010402010104000100040301020405 +01000404010004ff04ad0001040106010001040a06010001040106010409010004030101 +040101000401010104010100040401000402010004020100040101010401010004040100 +040401000403010004020100040801010401010004010100040201000401010104010100 +0401010004000100040001000401010004020100040401000404010004ff04ad00010401 +06010001040a060100010401060104070101040401000402010004010100040801000402 +010004020100040101000408010004040100040401000401010004080100040201000401 +0100040201000401010004050100040001000400010004050100040401000405010104ff +04ab0001040106010001040a060100010401060104090100040301000402010004010100 +040801000402010004020100040101000408010004040100040401000401010004080100 +040201000401010004020100040101000405010004000100040001000402010304040100 +0404010004ff04ad0001040106010001040a060100010401060104090100040301000402 +010004010100040801000402010004020100040101000408010004040100040501000400 +010004080100040201000401010004020100040101000405010004000100040001000401 +010004020100040401000404010004ff04ad0001040106010001040a0601000104010601 +040901000403010104010100040101000408010004020100040201000401010004080100 +040401000405010104040101040201000402010004010100040201000401010004050100 +0400010004000100040101000402010004040100040401000405010104ff04a500010401 +06010001040a060100010401060104090100040301000400010104020100040801000403 +010204020100040801000405010104040100040401010402010004020100040201020402 +01000405010004000100040001000402010304040100040401000405010104ff04a50001 +040106010001040a060100010401060104090100040301000432010004050100042e0100 +0406010004ff04a50001040106010001040a0601000104010601040a010104010100042f +01000400010004040101042d01010405010104ff04a60001040106010001040a06010001 +04010601040e01000430010004ff04e60001040106010001040a0601000104010601040a +0101049b010104ff047d0001040106010001040a06010001040106010409010004620100 +043101000408010004ff047c0001040106010001040a060100010401060104090100042e +0102041401000419010004040101040b01000405010104040101040b0101040201000407 +010004ff047c0001040106010001040a0601000104010601040901000430010004140100 +041801000404010004010100040901010404010004010100040201000401010004090100 +04010100040201000406010004ff047c0001040106010001040a06010001040106010409 +010004040101040001000401010004000101040301020402010004020100040101000400 +0101040c010004030102040301020403010104000100040201020402010004000101040a +010004050100040101000408010004000100040401000401010004020100040101000409 +010004010100040301000405010004ff047c0001040106010001040a0601000104010601 +040901000403010004010101040101010401010004010100040201000401010004020100 +0401010104010100040b0100040201000402010004010100040201000401010004010101 +04010100040201000401010104010100040801000406010004010100040a010004040100 +0401010004020100040101000409010004010100040401000404010004ff047c00010401 +06010001040a060100010401060104070101040401000402010004010100040501000402 +010004010100040201000401010004020100040b01000402010004020100040501000401 +010004020100040101000402010004010100040b01000407010004010100040a01000404 +01000401010004020100040101000409010004010100040501000404010104ff047a0001 +040106010001040a06010001040106010409010004030100040201000401010004050100 +0402010004010100040201000401010004020100040b0100040201040402010304010100 +040201000401010404010100040c01000406010004010100040a01000404010004010100 +04020100040101000409010004010100040401000404010004ff047c0001040106010001 +040a06010001040106010409010004030100040201000401010004050100040201000401 +0100040201000401010004020100040b0100040201000405010004020100040101000402 +01000401010004050100040d01000405010004010100040a010004040100040101000402 +0100040101000409010004010100040301000405010004ff047c0001040106010001040a +060100010401060104090100040301000401010104010100040501000402010004010100 +040101010401010104010100040b01000402010004020100040101000402010004010100 +040101010401010004020100040101000407010104040100040401000401010004030101 +040401000404010004010100040201000401010004030101040301000401010004020100 +040601000405010104ff04740001040106010001040a0601000104010601040901000404 +010104000100040101000406010204030101040001000401010004000101040c01000403 +010204030103040201010400010004020102040201000407010104050100040401010404 +0101040201040403010104040101040401010404010104020100040701000405010104ff +04740001040106010001040a060100010401060104090100040701000416010004040105 +042e01000406010004310100040801000406010004ff04740001040106010001040a0601 +000104010601040a010104010100040201000416010004370101044201010405010104ff +04750001040106010001040a0601000104010601040f01020417010004ff04fc00010401 +06010001040a0601000104010601040a0101045c010104ff04bc0001040106010001040a +0601000104010601040901000460010004ff04bb0001040106010001040a060100010401 +06010409010004030100042b01000418010204030102040301020404010004ff04bb0001 +040106010001040a06010001040106010409010004030100044401000402010004010100 +0402010004010100040201000403010004ff04bb0001040106010001040a060100010401 +060104090100040301000400010104030102040301020402010004000101040a01020403 +01020402010404020102040d010004050100040501000403010004ff04bb000104010601 +0001040a0601000104010601040901000403010104010100040101000402010004010100 +040201000401010104010100040801000402010004040100040601000401010004020100 +040c010004050100040501000403010004ff04bb0001040106010001040a060100010401 +060104070101040401000402010004010100040201000405010004010100040201000408 +010004080100040501000402010004020100040b010004040101040401010405010104ff +04b90001040106010001040a060100010401060104090100040301000402010004010104 +04020103040101000402010004090102040501000404010004030104040a010004070100 +040501000403010004ff04bb0001040106010001040a0601000104010601040901000403 +0100040201000401010004050100040201000401010004020100040c0100040401000403 +010004040100040d010004080100040501000403010004ff04bb0001040106010001040a +060100010401060104090100040301000402010004010100040201000401010004020100 +040101010401010004080100040201000404010004020100040501000402010004030101 +0402010004050100040201000401010004020100040301000405010104ff04b300010401 +06010001040a060100010401060104090100040301000402010004020102040301030401 +010004000101040a01020405010004020104040201020404010104020104040201020403 +0102040401000405010104ff04b30001040106010001040a060100010401060104090100 +041801000404010504200100041901000406010004ff04b30001040106010001040a0601 +000104010601040a01010416010004290101041801010405010104ff04b4000104010601 +0001040a06010001040106010423010004ff04ff04030001040106010001040a06010001 +04010601040a0101045c010104ff04bc0001040106010001040a06010001040106010409 +01000460010004ff04bb0001040106010001040a060100010401060104090100040c0100 +041101000416010004190100040401020404010004ff04bb0001040106010001040a0601 +00010401060104090100040c0100041101000430010104030100040201000403010004ff +04bb0001040106010001040a060100010401060104090100040401020402010404020102 +040301020402010004010100040a01020403010204020104040201020409010004000100 +040701000403010004ff04bb0001040106010001040a0601000104010601040901000403 +01000402010004030100040301000402010004010100040201000401010004000100040a +01000402010004040100040601000401010004020100040a0100040701000403010004ff +04bb0001040106010001040a060100010401060104070101040401000407010004070100 +0401010004050101040b010004080100040501000402010004020100040a010004060100 +0405010104ff04b90001040106010001040a060100010401060104090100040401020404 +0100040401030401010004050101040c0102040501000404010004030104040a01000405 +01000405010004ff04bb0001040106010001040a06010001040106010409010004070100 +040301000403010004020100040101000405010004000100040e01000404010004030100 +04040100040e0100040401000406010004ff04bb0001040106010001040a060100010401 +060104090100040301000402010004030100040301000402010004010100040201000401 +010004010100040901000402010004040100040201000405010004020100040301010404 +010004030100040701000405010104ff04b30001040106010001040a0601000104010601 +040901000404010204050101040201030402010204020100040201000409010204050100 +0402010404020102040401010402010404010104040301000405010104ff04b300010401 +06010001040a0601000104010601040901000425010504200100041201000406010004ff +04b30001040106010001040a0601000104010601040a0101044801010411010104050101 +04ff04b40001040106010001040a060100010401060104ff04ff04280001040106010001 +040a0601000104010601040a0101045c010104ff04bc0001040106010001040a06010001 +04010601040901000460010004ff04bb0001040106010001040a06010001040106010409 +0100041501000411010004060100041f0102040401010404010004ff04bb000104010601 +0001040a0601000104010601040901000415010004110100042601000402010004020100 +040101000403010004ff04bb0001040106010001040a0601000104010601040901000403 +010004000101040301020403010104000100040101000402010004020102040201040402 +010204030102040201000400010104030102040d010004020100040101000403010004ff +04bb0001040106010001040a060100010401060104090100040301010401010004010100 +040201000401010004010101040101000402010004010100040201000403010004060100 +040201000402010004010101040101000401010004020100040c01000402010004010100 +0403010004ff04bb0001040106010001040a060100010401060104070101040401000405 +010004020100040101000402010004010100040201000401010004070100040601000402 +010004020100040101000402010004010100040e010104030100040101000404010104ff +04b90001040106010001040a060100010401060104090100040301000405010404010100 +040201000401010004020100040101000407010004060100040201000402010004010100 +0402010004020102040d010004020100040101000403010004ff04bb0001040106010001 +040a06010001040106010409010004030100040501000405010004020100040101000402 +01000401010004070100040601000402010004020100040101000402010004050100040c +010004020100040101000403010004ff04bb0001040106010001040a0601000104010601 +040901000403010004050100040201000401010004010101040101000401010104010100 +040201000403010004060100040201000402010004010100040201000401010004020100 +0403010104020100040201000402010004010100040301000405010104ff04b300010401 +06010001040a060100010401060104090100040301000406010204030101040001000402 +010104000100040201020405010104040100040301020402010004020100040201020404 +01010403010204040101040401000405010104ff04b30001040106010001040a06010001 +0401060104090100044c0100041201000406010004ff04b30001040106010001040a0601 +000104010601040a010104480101041101010405010104ff04b40001040106010001040a +060100010401060104ff04ff04280001040106010001040a0601000104010601040a0101 +04890101049401010404010104f10001040106010001040a060100010401060104090100 +048a010004980100040501000403010304e80001040106010001040a0601000104010601 +040901000418010004300102040301020412010004060100041901000406010104090102 +040301020436010104030100041901020402010404010104040201020402010404030100 +040501000406010004e80001040106010001040a06010001040106010409010004180100 +0432010004050100041201000421010004050100040d0100040501000435010004050100 +041801000402010004010100040501000405010004020100040101000407010004050100 +0406010004e80001040106010001040a0601000104010601040901000404010104000100 +040201020402010004000101040201000400010104030102040301010400010004020102 +040a01020403010204050100040501000403010204030102040201040402010204030102 +0402010004000101040b0100040501000403010004020100040401000405010004030102 +040201000402010004020102040301020402010004000101040a01020404010004030104 +040201020402010004000101040901000405010004050100040901000401010004070100 +040501000406010004e80001040106010001040a06010001040106010409010004030100 +040101010401010004020100040101010401010004010101040101000401010004020100 +040101000401010104010100040201000408010004020100040101000402010004040100 +040501000402010004020100040101000402010004030100040601000402010004020100 +0401010104010100040a0100040301040401010004020100040401000405010004020100 +040201000401010004020100040101000402010004010100040201000401010104010100 +040801000402010004010104040301000403010004020100040101010401010004080100 +0405010304020103040601000401010304040100040501000406010004e8000104010601 +0001040a0601000104010601040701010404010004020100040501000401010004050100 +040201000405010004010100040201000401010004020100040801000405010004020100 +040401000405010004020100040201000401010004070100040601000402010004020100 +040101000402010004080101040601000403010004020100040401000405010004020100 +040501000400010004000100040101000402010004010100040201000401010004020100 +040c01000403010004050100040301000402010004010100040c01030406010004050100 +040301010406010004040101040401010404010004e80001040106010001040a06010001 +040106010409010004030100040201000402010304010100040501000402010004020103 +040101000402010004010104040801000405010004020100040401000405010004020104 +04010100040701000406010004020100040201000401010004020100040a010004050100 +040301000402010004040100040501000403010204020100040001000400010004010104 +0401010404010100040201000409010304030100040501000403010404010100040c0100 +040201000405010004050100040501000405010004030100040501000406010004e80001 +040106010001040a06010001040106010409010004030100040201000401010004020100 +0401010004050100040201000401010004020100040101000402010004010100040c0100 +040501000402010004040100040501000402010004050100040701000406010004020100 +040201000401010004020100040a01000405010004030100040201000404010004050100 +040601000401010004000100040001000401010004050100040501000402010004080100 +0402010004030100040501000403010004050100040c0100040201000401010004020100 +040101000402010004050100040101000402010004030100040501000406010004e80001 +040106010001040a06010001040106010409010004030100040101010401010004020100 +040101000405010104010100040101000402010004010100040101010401010004020100 +040801000402010004010100040201000404010004050100040201000402010004010100 +040201000403010004060100040201000402010004010100040201000403010104040100 +040501000403010004010101040401000405010004020100040201000401010004000100 +040001000401010004020100040101000402010004010101040101000408010004020100 +040301000405010004030100040201000401010004070101040201000402010004010100 +040201000401010004020100040101000402010004010100040201000403010004050100 +0406010004e80001040106010001040a0601000104010601040901000404010104000100 +0402010304010100040501000400010104030103040201010400010004020102040a0102 +040301020405010004050100040301020403010204050101040401000403010204020100 +040201000403010104040100040501000404010104000100040401000405010004030102 +040301000400010004030102040301020402010004000101040a01030403010004060101 +040201020402010004070101040301020403010204030102040301020403010204040100 +040501000406010004e80001040106010001040a06010001040106010409010004070100 +0421010004070105044a010004040100043b010004040105042701000427010004050100 +0403010304e80001040106010001040a0601000104010601040a01010401010004020100 +041d01000402010004560101040601010439010004300101042601010404010104f10001 +040106010001040a0601000104010601040f0102041f0102049c010004ff045400010401 +06010001040a060100010401060104ff04ff04280001040106010001040a060100010401 +060104ff04ff04280001040106010001040a060100010401060104ff04ff042800010401 +06010001040a060100010401060104ff04ff04280001040106010001040a060100010401 +060104ff04ff04280001040106010001040a060100010401060104ff04ff042800010401 +06010001040a060100010401060104ff04ff04280001040106010001040a060100010401 +060104ff04ff04280001040106010001040a060100010401060104ff04ff042800010401 +06010001040a060100010401060104ff04ff04280001040106010001040a060100010401 +060104ff04ff04280001040106010001040a060100010401060104ff04ff042800010401 +06010001040a060100010401060104ff04ff04280001040106010001040a060100010401 +060104ff04ff04280001040106010001040a060100010401060104ff04ff042800010401 +06010001040a060100010401060104ff04ff04280001040106010001040a060100010401 +060104ff04ff04280001040106010001040a060100010401060104ff04ff042800010401 +06010001040a060100010401060104ff04ff04280001040106010001060c000104010601 +04ff04ff04280001040106010000060d00010401060104ff04ff0428000104010601050e +00010401060104ff04ff042800010401060100100401060104ff04ff0428000104010601 +0500000c060000010401060104ff04ff0428000104010601050000010408060105000001 +0401060104ff04ff04280001040106010501000104070601050000010401060104ff04ff +04280001040106010501000104060601050100010401060104ff04ff0428000104010601 +0502000104050601050100010401060104ff04ff04280001040106010502000104040601 +050200010401060104ff04ff042800010401060105030001040306010502000104010601 +04ff04ff04280001040106010503000104020601050300010401060104ff04ff04280001 +040106010504000104010601050300010401060104ff04ff042800010401060105040001 +04000601050400010401060104ff04ff0428000104010601050500000602050400010401 +060104ff04ff0428000104010601050500000601050500010401060100ff00ff002a0401 +060105060601050500010401060000ff00ff002b04010601050606000506000104ff04ff +04300601001004ff04ff04300600001104ff04ff04ff04ff04ff04ff04ff04ff04ff04ff +04ff04ff04ff0498010204ff04ff044001000401010004ff04ff043f0100040201000402 +010204020100040001010403010204ff04ff042a01000402010004010100040201000401 +010104010100040101000402010004ff04ff042901000402010004010100040201000401 +010004020100040101000402010004ff04ff042901000402010004010100040201000401 +0100040201000401010404ff04ff04290100040201000401010004020100040101000402 +01000401010004ff04ff042d010004010100040201000402010004010100040201000401 +01000402010004ff04ff042901020404010204020100040201000402010204ff04ff04ff +04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04ff04c1 +%%EndData +end +%%PageTrailer +%%Trailer +%%BoundingBox: 0 73 377 347 +%%EOF diff --git a/lib/appmon/doc/src/ref_man.xml b/lib/appmon/doc/src/ref_man.xml new file mode 100644 index 0000000000..ab9c3d5fdc --- /dev/null +++ b/lib/appmon/doc/src/ref_man.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE application SYSTEM "application.dtd"> + +<application xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Appmon Reference Manual</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <description> + <p>The Application Monitor, <em>Appmon</em>, is a graphical utility used + to supervise applications executing either locally or on remote nodes. + The process tree of an application can furthermore be monitored.</p> + </description> + <xi:include href="appmon.xml"/> +</application> + diff --git a/lib/appmon/doc/src/warning.gif b/lib/appmon/doc/src/warning.gif Binary files differnew file mode 100644 index 0000000000..96af52360e --- /dev/null +++ b/lib/appmon/doc/src/warning.gif diff --git a/lib/appmon/ebin/.gitignore b/lib/appmon/ebin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/appmon/ebin/.gitignore diff --git a/lib/appmon/info b/lib/appmon/info new file mode 100644 index 0000000000..c33a50d106 --- /dev/null +++ b/lib/appmon/info @@ -0,0 +1,5 @@ +group: tools +short: A utility used to supervise Applications executing on several +short: Erlang nodes + + diff --git a/lib/appmon/priv/Makefile b/lib/appmon/priv/Makefile new file mode 100644 index 0000000000..9af4fbd228 --- /dev/null +++ b/lib/appmon/priv/Makefile @@ -0,0 +1,65 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +include ../vsn.mk +VSN = $(APPMON_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/appmon-$(VSN) + +# +# Macros +# +HELP_FILES = \ + appmon_help.txt + +TOOLBAR_FILES = \ + appmon.tool \ + appmon.gif \ + start_info.html \ + main_frame.html \ + info_frames.html \ + blank.html + +# +# Rules +# + +debug opt: + +docs: + +clean: + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/priv + $(INSTALL_DATA) $(HELP_FILES) $(TOOLBAR_FILES) $(RELSYSDIR)/priv + +release_docs_spec: + +FORCE: diff --git a/lib/appmon/priv/appmon.gif b/lib/appmon/priv/appmon.gif Binary files differnew file mode 100644 index 0000000000..583fcb8311 --- /dev/null +++ b/lib/appmon/priv/appmon.gif diff --git a/lib/appmon/priv/appmon.tool b/lib/appmon/priv/appmon.tool new file mode 100644 index 0000000000..93a469c6a4 --- /dev/null +++ b/lib/appmon/priv/appmon.tool @@ -0,0 +1,24 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +{version,"1.2"}. +[{config_func,{appmon_web,configData,[]}}, +{tool,"Appmon"}, + {start,{appmon,start,[]}}, + {icon,"appmon.gif"}, + {message,"Application Monitor"}, + {html,"../doc/html/index.html"}]. diff --git a/lib/appmon/priv/appmon_help.txt b/lib/appmon/priv/appmon_help.txt new file mode 100644 index 0000000000..f1685be4d8 --- /dev/null +++ b/lib/appmon/priv/appmon_help.txt @@ -0,0 +1,154 @@ + + + + Help for the application monitor system + --------------------------------------- + + + + + + The monitor system has two types of windows, the node window + which opens when appmon:start() is evaluated, and the + application window which opens when an application in the node + window is clicked on. + + All nodes that are known to appmon is shown in the node + window, normally this is all Erlang nodes visible with the + nodes() command. + + +The Node window +--------------- + + The node window monitors nodes. At the top there is a menubar + and below that, each known node is shown separated with a thin + line from the others. A node is represented by its name as + root of its application tree. The node name pictures the + application controller on that node. The name itself is a menu + where operations on the node can be performed (rebooting it + for instance). To the far left is a load meter (like those on + a tape deck) which measures the current load at the + node. Below the node name (the application controller) is a + tree with applications, clicking on these applications starts + the application monitor. + + + The top window menubar + ---------------------- + + File:Quit - Stop the monitor. + + Options: + Load: time - Load is calculated (roughly) as processor time. + Load: queue - Load is calculated as the length of the ready + queue. + Load: prog - A progressive scale is used for load values. + Load: linear - A linear scale is used for load values. + + Help - Prints this message. + + + The application controller menu + ------------------------------- + Reboot - Reboot the node + Restart - Restart the node + Stop - Stop the node + + + The load meter + -------------- + + Load can be measured as processor time / elapsed time or as + the length of the runtime queue, depending on the setting in + the Options menu. + + +The Application window +---------------------- + + The application window monitors an application. It will + automaticly update the window every other second or so if + there are any changes in the process tree. At the top there is + a menubar followed by a toolbar and then the application + tree. Application trees come in two flavours: supervision + view, where a strict supervision tree is shown, and process + view, where all linked processes in the application is shown. + + + The application window menubar + ------------------------------ + + File:Quit - Quit the application window. + + Options:Refresh - Update process information and refresh + screen. + + Options:Sup. view + - Show strict supervision tree only. + + Options:Proc. view + - Show all linked processes. + + Help - Prints this message. + + + The application window toolbar + ------------------------------ + + The application toolbar controls the actions of the mouse + pointer. Clicking on a process in the application window have + different meaning depending on which tool is selected. The + procedure is to first press a button (T for trace for example) + and then click on the process that should be traced. + + Info - Process information is printed in the shell. This mode + is default and automaticly returned to after a mouse click. + + Send - Send a message to the clicked process. A window will + pop up where the message can be written (and you can also + change the destination pid). Double clicking on this button + pops up a window where pid and message can be filled in. + + Trace - Toggle trace on/off on the process. Note that not all + processes respond to the sys:trace call. + + Kill - Send a non-trappable exit signal to the process. + + +Technical Detail +---------------- + + Files and distribution + ---------------------- + + Appmon is a distributed program but all graphics is handled on + one node (the one it is started on) so GS need only to be + loaded on that single node. All real monitoring is done in a + single module (appmon_info) being run on each node which acts + as an information centre. The various windows (node and + application) then subscribe for information. + + In summary: only the appmon_info module must be accessible by + the clients, the rest of the appmon files are only needed at + the server. + + Trouble shooting + ---------------- + + Q. Why doesn't all my nodes show up in the node window? + + A 1. Are the nodes visible with the nodes() command in the + shell? If not you must do net:ping(NodeName) to add nodes to + the Erlang distribution. + + A 2. Is the appmin_info module loadable at the missing + node(s)? + + Q. Why doesn't the application window show my application + supervision structure? + + A. Does your application have a real application master? It is + absolutely necessary that your top process behaves as a + supervisor should (a program is not supervised just because it + is started with application:start). diff --git a/lib/appmon/priv/blank.html b/lib/appmon/priv/blank.html new file mode 100644 index 0000000000..44e86908a0 --- /dev/null +++ b/lib/appmon/priv/blank.html @@ -0,0 +1,6 @@ +<HTML> +<HEAD></HEAD> +<BODY BGCOLOR="#FFFFFF"> + +</BODY> +</HTML>
\ No newline at end of file diff --git a/lib/appmon/priv/info_frames.html b/lib/appmon/priv/info_frames.html new file mode 100644 index 0000000000..9320364883 --- /dev/null +++ b/lib/appmon/priv/info_frames.html @@ -0,0 +1,9 @@ +<HTML> +<HEAD> +<TITLE>WebAppmon </TITLE> +</HEAD> +<FRAMESET ROWS="85%,15%" BORDER="0"> +<FRAME NAME="main" SRC="./start_info.html"> +<FRAME NAME="proc_data" SRC="./blank.html"> +</FRAMESET> +</HTML>
\ No newline at end of file diff --git a/lib/appmon/priv/main_frame.html b/lib/appmon/priv/main_frame.html new file mode 100644 index 0000000000..57e540a2c1 --- /dev/null +++ b/lib/appmon/priv/main_frame.html @@ -0,0 +1,9 @@ +<HTML> +<HEAD> +<TITLE>WebAppmon </TITLE> +</HEAD> +<FRAMESET COLS="15%,85%" > + <FRAME NAME="left" SRC="../../erl/appmon_web/node_info"> + <FRAME NAME="base_frames" SRC="./info_frames.html"> +</FRAMESET> +</HTML>
\ No newline at end of file diff --git a/lib/appmon/priv/start_info.html b/lib/appmon/priv/start_info.html new file mode 100644 index 0000000000..580319beb1 --- /dev/null +++ b/lib/appmon/priv/start_info.html @@ -0,0 +1,31 @@ +<HTML> +<HEAD> +</HEAD> +<BODY BGCOLOR="#FFFFFF"> +<TABLE WIDTH=100% HEIGHT=100%> +<TR VALIGN="middle"> +<TD ALIGN="center"> + +<TABLE WIDTH="60%"> +<TR> +<TD ALIGN="center"> +<FONT SIZE=6>Welcome to the Web based User Interface to Appmon +</FONT></TD> +</TR> + +<TR> +<TD><BR><BR><BR><BR> +</TD> +</TR> + +<TR> +<TD ALIGN="center"> +</TD> +</TR> +</TABLE> + +</TD> +</TR> +</TABLE> +</BODY> +</HTML>
\ No newline at end of file diff --git a/lib/appmon/src/Makefile b/lib/appmon/src/Makefile new file mode 100644 index 0000000000..43f4f085b8 --- /dev/null +++ b/lib/appmon/src/Makefile @@ -0,0 +1,101 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1996-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(APPMON_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/appmon-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES= \ + appmon \ + appmon_a \ + appmon_dg \ + appmon_info \ + appmon_place \ + appmon_txt \ + appmon_lb \ + process_info \ + appmon_web + +HRL_FILES= appmon_dg.hrl + +ERL_FILES= $(MODULES:%=%.erl) + +TARGET_FILES= $(MODULES:%=../ebin/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) + +APP_FILE= appmon.app +APPUP_FILE= appmon.appup + +APP_SRC= $(APP_FILE).src +APPUP_SRC= $(APPUP_FILE).src + +APP_TARGET= ../ebin/$(APP_FILE) +APPUP_TARGET= ../ebin/$(APPUP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += +warn_obsolete_guard + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f core + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +$(APP_TARGET): $(APP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + +release_docs_spec: + diff --git a/lib/appmon/src/appmon.app.src b/lib/appmon/src/appmon.app.src new file mode 100644 index 0000000000..2e1aa3ef3b --- /dev/null +++ b/lib/appmon/src/appmon.app.src @@ -0,0 +1,24 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +{application, appmon, + [{description, "DEVTOOLS CXC 138 16"}, + {vsn, "%VSN%"}, + {modules, [appmon, appmon_a, appmon_dg, appmon_info, + appmon_lb, appmon_place, appmon_txt,process_info,appmon_web]}, + {registered,[appmon, appmon_info, appmon_txt,webappmon_server,proc_info]}, + {applications, [kernel, stdlib]}]}. diff --git a/lib/appmon/src/appmon.appup.src b/lib/appmon/src/appmon.appup.src new file mode 100644 index 0000000000..0d918b6081 --- /dev/null +++ b/lib/appmon/src/appmon.appup.src @@ -0,0 +1,18 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +{"%VSN%",[],[]}. diff --git a/lib/appmon/src/appmon.erl b/lib/appmon/src/appmon.erl new file mode 100644 index 0000000000..6f5d2824d2 --- /dev/null +++ b/lib/appmon/src/appmon.erl @@ -0,0 +1,1079 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +-module(appmon). +-behaviour(gen_server). + +%%%--------------------------------------------------------------------- +%%% Appmon main module. +%%% Creates the main window and receives load and application +%%% information from all connected nodes. +%%%--------------------------------------------------------------------- + +%% External exports +-export([start/0, stop/0]). + +%% gen_server callbacks +-export([init/1, handle_cast/2, handle_info/2, terminate/2]). +-export([handle_call/3, code_change/3]). % not used + +%% Canvas button data +-record(canvasbutton, {text, ul, ll, rect, x, y, w, h}). + +%% Options - all the fields are GS radio buttons +-record(options, {single, many, time, queue, prog, linear}). + +%% Main window data +-record(win, {name, % atom() Monitored node + window, % gsobj() + wwindow, % int() Window width + hwindow, % int() Window height + options, % #options{} + canvas, % gsobj() + wcanvas, % int() Canvas width + hcanvas, % int() Canvas height + l1, l2, % gsobj() Canvas lines + leds, % [gsobj()] Load meter + nodelabel, % {gsobj(),gsobj()} + appobjs=[], % [gsobj()] Buttons etc. + nodemenu}). % gsobj() Node menu + +%% Node data +-record(mnode, {name, % atom() Node name + status, % alive | dead + pid, % pid() + apps, % [{Pid,App,Descr}] + load}). % {Old, New} + +%% Internal state data +-record(state, {gs, % pid() + wins=[], % [#win()] GUIs + window_mode, % single | many + load_mode1, % time | queue + load_mode2, % prog | linear + lbpid, % pid() + mnodes=[]}). % [#mnode{}] + +%%%--------------------------------------------------------------------- +%%% External exports +%%%--------------------------------------------------------------------- + +start() -> + gen_server:start({local, appmon}, ?MODULE, [], []). + +stop() -> + gen_server:cast(appmon, stop). + + +%%%--------------------------------------------------------------------- +%%% gen_server callbacks +%%%--------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Func: init/1 +%% Returns: {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%%---------------------------------------------------------------------- +init([]) -> + process_flag(trap_exit, true), + + %% Subscribe to {nodeup,Node} and {nodedown,Node} messages + net_kernel:monitor_nodes(true), + + LbPid = appmon_lb:start(self ()), + + %% Check which remote nodes have appmon code available (OTP-4887) + NodesOk = lists:filter(fun(Node) -> check_node(Node) end, nodes()), + Nodes = [node()|NodesOk], + + %% Start monitoring the existing nodes + MNodes = mk_mnodes(Nodes, LbPid), + + %% Draw the main window + GS = gs:start([{kernel,true}]), + GUI = draw_win(GS, node()), + + %% Update the Nodes menu with all known nodes + lists:foreach(fun(Node) -> + display_addnode(GUI, Node) + end, + Nodes), + + %% Mark the default options as selected in the Options menu + display_setopt(GUI, single), + display_setopt(GUI, time), + display_setopt(GUI, prog), + + {ok, #state{gs=GS, wins=[GUI], + window_mode=single, load_mode1=time, load_mode2=prog, + lbpid=LbPid, mnodes=MNodes}}. + +check_node(Node) -> + case rpc:call(Node, code, which, [appmon]) of + File when is_list(File) -> + true; + _ -> % non_existing (| cover_compiled) + false + end. + +%%---------------------------------------------------------------------- +%% Func: handle_call/3 +%% Returns: {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | (terminate/2 is called) +%% {stop, Reason, State} (terminate/2 is called) +%%---------------------------------------------------------------------- +handle_call(norequest, _From, State) -> + {reply, null, State}. + +%%---------------------------------------------------------------------- +%% Func: handle_cast/2 +%% Returns: {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} (terminate/2 is called) +%%---------------------------------------------------------------------- +handle_cast(stop, State) -> + {stop, normal, State}. + +%%---------------------------------------------------------------------- +%% Func: handle_info/2 +%% Returns: {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} (terminate/2 is called) +%%---------------------------------------------------------------------- +%% Load information from a node +handle_info({delivery, _Serv, load, Node, Load}, State) -> + + %% Update node information + MNode = get_mnode(Node, State#state.mnodes), + MNode1 = MNode#mnode{load=Load}, + MNodes = replace_mnode(Node, MNode1, State#state.mnodes), + + %% If Node is currently displayed, update graphics + case get_win(Node, State#state.wins) of + {ok, GUI} -> + display_load(GUI, Load); + false -> + ignore + end, + + {noreply, State#state{mnodes=MNodes}}; + +%% Application information from a node +handle_info({delivery, _Serv, app_ctrl, Node, Apps}, State) -> + + %% Update node information + MNode = get_mnode(Node, State#state.mnodes), + MNode1 = MNode#mnode{apps=Apps}, + MNodes = replace_mnode(Node, MNode1, State#state.mnodes), + + %% If Node is currently displayed, update graphics + Wins = case get_win(Node, State#state.wins) of + {ok, GUI} -> + draw_clear(GUI), + GUI1 = draw_apps(GUI, Apps), + replace_win(Node, GUI1, State#state.wins); + false -> + State#state.wins + end, + + appmon_lb:add_apps (State#state.lbpid, Apps, Node), + {noreply, State#state{wins=Wins, mnodes=MNodes}}; + +handle_info({nodeup, Node}, State) -> + + %% First, make sure appmon code is available at remode node, + %% or the node should be ignored (OTP-3591) + case check_node(Node) of + true -> + + %% If this is a previously unknown node, update window's + %% 'Nodes' menu + case get_mnode(Node, State#state.mnodes) of + false -> + display_addnode(State#state.wins, Node); + _OldMnode -> + ignore + end, + + %% Update node information (=> state is automatically + %% changed to 'alive') + MNode = mk_mnode(Node, State#state.lbpid), + MNodes = replace_mnode(Node, MNode, State#state.mnodes), + + %% If Node is currently displayed, update graphics + case get_win(Node, State#state.wins) of + {ok, GUI} -> + display_nodeup(GUI, Node); + false -> + ignore + end, + + appmon_lb:update_status(State#state.lbpid, Node, alive), + {noreply, State#state{mnodes=MNodes}}; + + false -> + {noreply, State} + end; + +handle_info({nodedown, Node}, State) -> + + %% If this is a previously unknown node, ignore the message. + %% (The situation occurs when failing to connect to another node). + %% Otherwise, update the node information. + case get_mnode(Node, State#state.mnodes) of + false -> + {noreply, State}; + MNode -> + MNode1 = MNode#mnode{status=dead}, + MNodes = replace_mnode(Node, MNode1, State#state.mnodes), + + %% If Node is currently displayed, update graphics + Wins = case get_win(Node, State#state.wins) of + {ok, GUI} -> + display_nodedown(GUI), + GUI1 = draw_clear(GUI), + replace_win(Node, GUI1, State#state.wins); + false -> + State#state.wins + end, + + appmon_lb:remove_node(State#state.lbpid, Node), + {noreply, State#state{wins=Wins, mnodes=MNodes}} + end; + +%% Application 'button' events +handle_info({gs, _Obj, buttonpress, Data, _Arg}, State) -> + {canvasbutton, CBtn, _App} = Data, + press(CBtn), + {noreply, State}; +handle_info({gs, _Obj, buttonrelease, Data, [_,X,Y|_]}, State) -> + {canvasbutton, CBtn, {application, App, Node}} = Data, + release(CBtn), + + %% Check that mouse button was released over the button! + L = CBtn#canvasbutton.x, R = L + CBtn#canvasbutton.w, + T = CBtn#canvasbutton.y, B = T + CBtn#canvasbutton.h, + if + X>L, X<R, Y>T, Y<B -> + MNode = get_mnode(Node, State#state.mnodes), + {value, {Pid, _App, _Descr}} = + lists:keysearch(App, 2, MNode#mnode.apps), + appmon_a:start(Node, App, Pid); + true -> + ignore + end, + {noreply, State}; + +handle_info({gs, _Button, click, Data, _Arg}, State) -> + ThisNode = node(), + case Data of + + %% File menu item + listbox -> + appmon_lb:open_win(State#state.lbpid, + parse_nodes(State#state.mnodes)), + {noreply, State}; + {close, WinObj} -> + {ok, GUI} = get_win2(WinObj, State#state.wins), + gs:destroy(WinObj), + + %% Terminate if this was the only open window + case remove_win(GUI#win.name, State#state.wins) of + [] -> + {stop, normal, State}; + Wins -> + {noreply, State#state{wins=Wins}} + end; + exit -> + {stop, normal, State}; + + %% Actions menu item + {action, Action, WinObj} -> + {ok, GUI} = get_win2(WinObj, State#state.wins), + Node = GUI#win.name, + + if + Node==ThisNode -> + case Action of + ping -> + %% Ignore - makes no sense to ping yourself + ignore; + _ -> % reboot | restart | stop + apply(init, Action, []) + end; + + Node/=ThisNode -> + case Action of + ping -> + net_adm:ping(Node); + _ -> % reboot | restart | stop + rpc:cast(Node, init, Action, []) + end + end, + {noreply, State}; + + %% Options menu item + {window_mode, Mode} -> + + %% Update windows so they all show the same options + lists:foreach(fun(GUI) -> + display_setopt(GUI, Mode) + end, + State#state.wins), + {noreply, State#state{window_mode=Mode}}; + + {option, Tag, Option} -> + + %% Update windows so they all show the same options + lists:foreach(fun(GUI) -> + display_setopt(GUI, Tag) + end, + State#state.wins), + + %% Update all appmon_info processes about which kind of + %% load data is desired + lists:foreach(fun(MNode) -> + appmon_info:load(MNode#mnode.pid, + MNode#mnode.name, + true, + Option) + end, + State#state.mnodes), + + if + Tag==time; Tag==queue -> + {noreply, State#state{load_mode1=Tag}}; + Tag==prog; Tag==linear -> + {noreply, State#state{load_mode2=Tag}} + end; + + %% Nodes menu item + {node, Node, WinObj} -> + + %% Check first if this window is already displayed + case get_win(Node, State#state.wins) of + {ok, GUI} -> + + %% Node is already displayed, raise its window + gs:config(GUI#win.window, raise), + + {noreply, State}; + + %% Node is not displayed + false -> + + %% Redraw existing window or create a new window + %% depending on window mode + case State#state.window_mode of + + single -> + {ok, GUI} = + get_win2(WinObj, State#state.wins), + + %% Clear window and correct the node name + draw_clear(GUI), + GUI1 = draw_nodename(GUI, Node), + + %% Update window with the correct node name + %% and the applications running at the node + MNode = get_mnode(Node, State#state.mnodes), + GUI2 = case MNode#mnode.status of + dead -> + display_nodedown(GUI1), + GUI1; + alive -> + display_nodeup(GUI1, Node), + draw_apps(GUI1, + MNode#mnode.apps) + end, + Wins = replace_win(GUI#win.name, GUI2, + State#state.wins), + + {noreply, State#state{wins=Wins}}; + + many -> + GUI = draw_win(State#state.gs, Node), + + %% Update Nodes menu with all known nodes - + %% use MNodes to get them in the right order + lists:foreach(fun(MNode) -> + Name = + MNode#mnode.name, + display_addnode(GUI, + Name) + end, + State#state.mnodes), + + %% Mark selected options in the Options menu + display_setopt(GUI, many), + display_setopt(GUI, State#state.load_mode1), + display_setopt(GUI, State#state.load_mode2), + + %% Add the applications running at the node + MNode = get_mnode(Node, State#state.mnodes), + + GUI1 = case MNode#mnode.status of + dead -> + display_nodedown(GUI), + GUI; + alive -> + display_nodeup(GUI, Node), + draw_apps(GUI, + MNode#mnode.apps) + end, + Wins = [GUI1|State#state.wins], + + {noreply, State#state{wins=Wins}} + end + end; + + %% Help menu = Help button + help -> + HelpFile = filename:join([code:lib_dir(appmon), + "doc", "html", "part_frame.html"]), + case State#state.wins of + [Win] -> + tool_utils:open_help(Win#win.window, HelpFile); + _ -> + tool_utils:open_help(State#state.gs, HelpFile) + end, + {noreply, State}; + + _Other -> + {noreply, State} + end; +handle_info({gs, WinObj, configure, _, [WWindow, HWindow|_]}, State) -> + {ok, GUI} = get_win2(WinObj, State#state.wins), + GUI1 = draw_resize(GUI, WWindow, HWindow), + display_scrollbar(GUI1), + Wins = replace_win(GUI#win.name, GUI1, State#state.wins), + {noreply, State#state{wins=Wins}}; +handle_info({gs, WinObj, destroy, _, _}, State) -> % OTP-1179 + {ok, GUI} = get_win2(WinObj, State#state.wins), + + %% Terminate if this was the only open window + case remove_win(GUI#win.name, State#state.wins) of + [] -> + {stop, normal, State}; + Wins -> + {noreply, State#state{wins=Wins}} + end; + +handle_info(stop, State) -> + {stop, normal, State}; +handle_info({'EXIT', Pid, Reason}, State) -> + case Reason of + shutdown -> + %% Appmon is being asked to shut down, eg during reboot + {stop, Reason, State}; + _ -> + case State#state.gs of + + %% GS exited, kill appmon + {0, Pid} -> + {stop, normal, State}; + + _ -> + {noreply, State} + end + end; +handle_info(_Info, State) -> + {noreply, State}. + +%%---------------------------------------------------------------------- +%% Func: terminate/2 +%% Purpose: Shutdown the server +%% Returns: any (ignored by gen_server) +%%---------------------------------------------------------------------- +terminate(_Reason, State) -> + bcast(State#state.mnodes, {kill}), + appmon_lb:stop(State#state.lbpid), + ok. + +%%---------------------------------------------------------------------- +%% Func: code_change/3 +%% Purpose: Convert process state when code is changed +%% Returns: {ok, NewState} +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +%%%--------------------------------------------------------------------- +%%% Internal functions +%%%--------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% MNode manipulating functions +%%---------------------------------------------------------------------- + +%% mk_mnodes(Nodes, LbPid) -> MNodes +%% Nodes -> [atom()] +%% LbPid -> pid() +%% MNodes -> [#mnode{}] +mk_mnodes([Node|Nodes], LbPid) -> + [mk_mnode(Node, LbPid) | mk_mnodes(Nodes, LbPid)]; +mk_mnodes([], _LbPid) -> + []. + +mk_mnode(Node, LbPid) -> + + %% Create an appmon process at the node + {ok, Pid} = appmon_info:start_link(Node, self(), []), + + appmon_lb:add_node(LbPid, Node), + appmon_info:load(Pid, Node, true, [{timeout,1000}]), + appmon_info:app_ctrl(Pid, Node, true, []), + + #mnode{name=Node, status=alive, pid=Pid}. + +%% get_mnode(Node, MNodes) -> MNode | false +%% Node -> atom() +%% MNodes -> [#mnode{}] +%% MNode -> #mnode{} +get_mnode(Node, MNodes) -> + case lists:keysearch(Node, #mnode.name, MNodes) of + {value, MNode} -> + MNode; + false -> + false + end. + +%% replace_mnode(Node, MNode, MNodes1) -> Mnodes2 +%% Node -> atom() +%% MNode -> #mnode{} +%% MNodes1 -> MNodes2 -> [#mnode{}] +%% Replaces, or adds if previously not included, the mnode with name +%% Node in MNodes1 with MNode. +replace_mnode(Node, MNode, [#mnode{name=Node} | MNodes]) -> + [MNode | MNodes]; +replace_mnode(Node, MNode, [MNode2 | MNodes]) -> + [MNode2 | replace_mnode(Node, MNode, MNodes)]; +replace_mnode(_Node, MNode, []) -> + [MNode]. + + +%%---------------------------------------------------------------------- +%% GUI list manipulating functions +%%---------------------------------------------------------------------- + +%% get_win(Node, Wins) -> Win +%% Node -> atom() +%% Wins -> [#win{}] +%% Win -> #win{} +get_win(Node, Wins) -> + case lists:keysearch(Node, #win.name, Wins) of + {value, Win} -> + {ok, Win}; + false -> + false + end. + +%% get_win2(WinObj, Wins) -> Win +%% Window -> gsobj() +%% Wins -> [#win{}] +%% Win -> #win{} +get_win2(WinObj, Wins) -> + case lists:keysearch(WinObj, #win.window, Wins) of + {value, Win} -> + {ok, Win}; + false -> + false + end. + +%% replace_win(Node, Win, Wins) -> Wins2 +%% Node -> atom() +%% Win -> #win{} +%% Wins -> Wins2 -> [#win{}] +replace_win(Node, Win, Wins) -> + lists:keyreplace(Node, #win.name, Wins, Win). + +%% remove_win(Node, Wins) -> Wins2 +%% Node -> atom() +%% Wins -> Wins2 -> [#win{}] +remove_win(Node, Wins) -> + lists:keydelete(Node, #win.name, Wins). + + + + +%%---------------------------------------------------------------------- +%% GUI manipulating functions +%%---------------------------------------------------------------------- +-define(PAD, 10). % Pad between objects +-define(PAD2, 4*?PAD). % Pad betw. node lbl and app + +-define(hMENUBAR, 25). % Note: Hardwired in Tcl/Tk + +-define(xNODELBL, 60). % Node label +-define(yNODELBL, 35). +-define(hNODELBL, 20). + +-define(xMETER, 5). % Meter +-define(yMETER, ?yNODELBL). +-define(wMETER, 20). +-define(hMETER, ?hNODELBL + ?PAD + ?PAD2 + ?hBTN). +-define(LEDCOUNT, 16). + +-define(xBTN, ?xNODELBL). % Application buttons +-define(yBTN, ?yNODELBL + ?hNODELBL + ?PAD + ?PAD2). +-define(wBTN, 70). % min width +-define(hBTN, 20). + +-define(wCANVAS, 470 + ?wMETER + 3*?PAD). % Canvas +-define(hCANVAS, ?yNODELBL + ?hNODELBL + ?PAD + ?PAD2 + ?hBTN + 2*?PAD). + +-define(wWIN, ?wCANVAS). % Window +-define(hWIN, ?hMENUBAR + ?hCANVAS). + +%%--Main window--------------------------------------------------------- + +draw_win(GS, Node) -> + + %% Main window + NodeStr = atom_to_list(Node), + Win = gs:create(window, GS, [{title, + "APPMON: Overview on " ++ NodeStr}, + {width, ?wWIN}, {height, ?hWIN}, + {configure, true}]), + Canvas = gs:create(canvas, Win, [{x, 0}, {y, ?hMENUBAR}, + {width, ?wCANVAS}, + {height, ?hCANVAS}]), + L1 = gs:create(line, Canvas, [{coords, + [{0,?yNODELBL-?PAD}, + {?wCANVAS,?yNODELBL-?PAD}]}]), + L2 = gs:create(line, Canvas, [{coords, + [{0,?hCANVAS-?PAD}, + {?wCANVAS,?hCANVAS-?PAD}]}]), + + %% Standard buttons + MenuBar = gs:create(menubar, Win, [{height, ?hMENUBAR}]), + + FileMenuBtn = gs:create(menubutton, MenuBar, + [{label, {text,"File"}}]), + FileMenu = gs:create(menu, FileMenuBtn, []), + gs:create(menuitem, FileMenu, [{label, {text,"Show List Box..."}}, + {data, listbox}]), + gs:create(menuitem, FileMenu, [{label, {text, "Close"}}, + {data, {close, Win}}]), + gs:create(menuitem, FileMenu, [{itemtype, separator}]), + gs:create(menuitem, FileMenu, [{label, {text, "Exit"}}, + {data, exit}]), + + ActionMenuBtn = gs:create(menubutton, MenuBar, + [{label,{text,"Actions"}}]), + ActionMenu = gs:create(menu, ActionMenuBtn, []), + gs:create(menuitem, ActionMenu, [{label, {text,"Reboot"}}, + {data, {action, reboot, Win}}]), + gs:create(menuitem, ActionMenu, [{label, {text,"Restart"}}, + {data, {action, restart, Win}}]), + gs:create(menuitem, ActionMenu, [{label, {text,"Stop"}}, + {data, {action, stop, Win}}]), + gs:create(menuitem, ActionMenu, [{label, {text,"Ping"}}, + {data, {action, ping, Win}}]), + + OptMenuBtn = gs:create(menubutton, MenuBar, + [{label, {text,"Options"}}]), + OptMenu = gs:create(menu, OptMenuBtn, []), + G0 = now(), % Group identity unique per window! + SMI = gs:create(menuitem, OptMenu, [{label, {text,"One window"}}, + {itemtype, radio}, {group, G0}, + {data, {window_mode, single}}]), + MMI = gs:create(menuitem, OptMenu, [{label, {text,"Many windows"}}, + {itemtype, radio}, {group, G0}, + {data, {window_mode, many}}]), + gs:create(menuitem, OptMenu, [{itemtype, separator}]), + G1 = now(), + TMI = gs:create(menuitem, OptMenu, [{label, {text,"Load: time"}}, + {itemtype, radio}, {group, G1}, + {data, + {option, time, + [{load_method,time}]}}]), + QMI = gs:create(menuitem, OptMenu, [{label, {text,"Load: queue"}}, + {itemtype, radio}, {group, G1}, + {data, + {option, queue, + [{load_method,queue}]}}]), + G2 = now(), + PMI = gs:create(menuitem, OptMenu, + [{label, {text,"Load: progressive"}}, + {itemtype, radio}, {group, G2}, + {data, {option, prog, [{load_scale,prog}]}}]), + LMI = gs:create(menuitem, OptMenu, [{label, {text,"Load: linear"}}, + {itemtype, radio}, {group, G2}, + {data, + {option, linear, + [{load_scale,linear}]}}]), + + NodeMenuBtn = gs:create(menubutton, MenuBar, + [{label, {text,"Nodes"}}]), + NodeMenu = gs:create(menu, NodeMenuBtn, []), + + HelpMenuBtn = gs:create(menubutton, MenuBar, + [{label, {text,"Help"}}, {side, right}]), + HelpMenu = gs:create(menu, HelpMenuBtn, []), + gs:create(menuitem, HelpMenu, [{label, {text,"Help"}}, + {data, help}]), + + %% Meter + HLed = trunc((?hMETER)/(?LEDCOUNT)), + Leds = draw_leds(?LEDCOUNT, Canvas, ?yMETER, HLed, []), + leds_down(Leds, ?LEDCOUNT, 0), + gs:create(text, Canvas, [{coords, + [{?xMETER, ?yMETER+HLed*?LEDCOUNT}]}, + {anchor, nw}, + {font, {screen,8}}, + {text, "Load"}]), + gs:create(text, Canvas, [{coords, [{?xMETER+?wMETER, ?yMETER}]}, + {anchor, nw}, + {font, {screen,8}}, + {text, "Hi"}]), + gs:create(text, Canvas, [{coords, [{?xMETER+?wMETER, + ?yMETER+HLed*?LEDCOUNT}]}, + {anchor, w}, + {font, {screen,8}}, + {text, "Lo"}]), + + %% Node label + WNodeLbl = 8*length(NodeStr)+10, + NLRect = gs:create(rectangle, Canvas, + [{coords, [{?xNODELBL,?yNODELBL}, + {?xNODELBL+WNodeLbl, + ?yNODELBL+?hNODELBL}]}, + {fill, black}]), + Xc = ?xNODELBL + round(WNodeLbl/2), + Yc = ?yNODELBL + round(?hNODELBL/2), + NLText = gs:create(text, Canvas, [{text, NodeStr}, + {fg, {250,235,215}}, + {coords, [{Xc,Yc}]}, + {anchor, c}]), + NodeLbl = {NLRect, NLText}, + + gs:config(Win, {map, true}), + #win{name=Node, + window=Win, wwindow=?wWIN, hwindow=?hCANVAS, + options=#options{single=SMI, many=MMI, + time=TMI, queue=QMI, prog=PMI, linear=LMI}, + canvas=Canvas, wcanvas=?wCANVAS, hcanvas=?hCANVAS, + l1=L1, l2=L2, leds=Leds, nodelabel=NodeLbl, nodemenu=NodeMenu}. + +draw_leds(N, Canvas, Y, HLed, Leds) when N>0 -> + Led = gs:create(rectangle, Canvas, + [{coords, + [{?xMETER,Y}, {?xMETER+?wMETER,Y+HLed}]}]), + draw_leds(N-1, Canvas, Y+HLed, HLed, [Led | Leds]); +draw_leds(0, _Canvas, _Y, _HLed, Leds) -> + Leds. + +%%--Draw functions------------------------------------------------------ +%% Functions that modify the GUI and its data (win{}) + +%% Display the node name in the window title +%% (The name in the node label is changed by display_nodeup|nodedown) +%% Used when a changing the node to display +draw_nodename(GUI, Node) -> + NodeStr = atom_to_list(Node), + gs:config(GUI#win.window, + {title, "APPMON: Overview on " ++ NodeStr}), + GUI#win{name=Node}. + +%% Resize the canvas (when the window has been resized) +draw_resize(GUI, W, H) -> + Hc = H - ?hMENUBAR, + gs:config(GUI#win.canvas, [{width, W}, {height, Hc}]), + Yline1 = ?yNODELBL-?PAD, + Yline2 = ?hCANVAS-?PAD, + gs:config(GUI#win.l1, [{coords, [{0,Yline1},{W,Yline1}]}]), + gs:config(GUI#win.l2, [{coords, [{0,Yline2},{W,Yline2}]}]), + GUI#win{wwindow=W, hwindow=Hc}. + +%% Clear the GUI from applications and connecting lines +draw_clear(GUI) -> + draw_clear2(GUI#win.appobjs), + gs:config(GUI#win.canvas, [{hscroll, false}]), + GUI#win{appobjs=[]}. +draw_clear2([CBtn | AppObjs]) when is_record(CBtn, canvasbutton) -> + gs:destroy(CBtn#canvasbutton.text), + gs:destroy(CBtn#canvasbutton.ul), + gs:destroy(CBtn#canvasbutton.ll), + gs:destroy(CBtn#canvasbutton.rect), + draw_clear2(AppObjs); +draw_clear2([GSObj | AppObjs]) -> + gs:destroy(GSObj), + draw_clear2(AppObjs); +draw_clear2([]) -> + ignore. + +%% Display the applications, which are a list of tuples: {Pid,App,Descr} +%% Display them in the reversed order to get them chronologically +%% from left to right. +draw_apps(GUI, Apps) -> + {AppObjs, WCanvas} = draw_apps(GUI, lists:reverse(Apps), ?xNODELBL, + undefined, 0, []), + NewGUI = GUI#win{wcanvas=WCanvas, appobjs=AppObjs}, + display_scrollbar(NewGUI), + NewGUI. + +draw_apps(GUI, [App | Apps], X, Lx0, N, GSObjs) -> + + %% Some necessary data + {_Pid, AppName, _Descr} = App, + Text = atom_to_list(AppName), + Width = max(8*length(Text)+10, ?wBTN), + + %% Connect the application to the node label with a line + %% Lx0 = leftmost X coordinate (above previous application button) + %% Lx = X coordinate, Ly1, Ly2 = top and bottom Y coordinates + Lx = X + trunc(Width/2), + Line = case N of + %% First (leftmost application) - draw a vertical line + %% between the node label and application button + 0 -> + Ly1 = ?yNODELBL + ?hNODELBL +?PAD, + Ly2 = Ly1 + ?PAD2, + gs:create(line, GUI#win.canvas, + [{coords, [{Lx, Ly1}, {Lx, Ly2}]}]); + %% Nth application, N>1 - draw a horizontal line from + %% line connecting to the previous application button, + %% to above this application button, then vertically down + %% to the application button + _ -> + Ly1 = ?yNODELBL + ?hNODELBL + ?PAD + ?PAD2/2, + Ly2 = Ly1 + ?PAD2/2, + gs:create(line, GUI#win.canvas, + [{coords, [{Lx0, Ly1}, {Lx, Ly1}, + {Lx, Ly2}]}]) + end, + + %% The application is represented using a 'canvasbutton' + Data = {application, AppName, GUI#win.name}, + AppBtn = canvasbutton(GUI#win.canvas, Text, X, ?yBTN, Width, ?hBTN, + Data), + + draw_apps(GUI, Apps, X+Width+?PAD, Lx, N+1, [AppBtn, Line|GSObjs]); +draw_apps(_GUI, [], X, _N, _Lx0, GSObjs) -> + {GSObjs, X}. + +%%--Display functions--------------------------------------------------- +%% Functions that modify the GUI but not its data + +%% Add a new node to the Nodes menu +%% Used when a new node has connected +display_addnode([GUI|GUIs], Node) -> + display_addnode(GUI, Node), + display_addnode(GUIs, Node); +display_addnode([], _Node) -> + ignore; +display_addnode(GUI, Node) -> + Txt = "Show " ++ atom_to_list(Node), + gs:create(menuitem, GUI#win.nodemenu, + [{label, {text,Txt}}, + {data, {node, Node, GUI#win.window}}]). + +%% Show that a node has come back up +display_nodeup(GUI, Node) -> + {Rect, Text} = GUI#win.nodelabel, + + %% Check coordinates for the rectangle and compute the new width + [{L, T}, {_R, B}] = gs:read(Rect, coords), + NodeStr = atom_to_list(Node), + W = 8*length(NodeStr)+10, + + gs:config(Rect, [{coords, [{L, T}, {L+W, B}]}, {fill, black}]), + gs:config(Text, [{text, NodeStr}, {fg, {250,235,215}}, + {coords, + [{L+round(W/2), T+round((?hNODELBL)/2)}]}]). + +%% Show that a node has gone down +display_nodedown(GUI) -> + {Rect, Text} = GUI#win.nodelabel, + + [{L, T}, {_R, B}] = gs:read(Rect, coords), + gs:config(Rect, [{coords, [{L, T}, {L+114, B}]}, {fill, gray}]), + gs:config(Text, [{text, "No connection"}, {fg, black}, + {coords, [{L+57, T+round((?hNODELBL)/2)}]}]). + +%% Add/remove scrollbars as necessary +display_scrollbar(GUI) -> + + WWindow = GUI#win.wwindow, + HWindow = GUI#win.hwindow, + WCanvas = GUI#win.wcanvas, + HCanvas = GUI#win.hcanvas, + if + WCanvas>WWindow -> + gs:config(GUI#win.canvas, + [{hscroll, bottom}, + {scrollregion,{0,0,WCanvas,HCanvas}}]); + true -> + gs:config(GUI#win.canvas, [{hscroll, false}]) + end, + if + HCanvas>HWindow -> + gs:config(GUI#win.canvas, + [{vscroll, left}, + {scrollregion,{0,0,WCanvas,HCanvas}}]); + + true -> + gs:config(GUI#win.canvas, [{vscroll, false}]) + end. + +%% Select option radio buttons +display_setopt(GUI, Option) -> + gs:config(radiobutton(GUI, Option), {select,true}). + +radiobutton(GUI, single) -> (GUI#win.options)#options.single; +radiobutton(GUI, many) -> (GUI#win.options)#options.many; +radiobutton(GUI, time) -> (GUI#win.options)#options.time; +radiobutton(GUI, queue) -> (GUI#win.options)#options.queue; +radiobutton(GUI, prog) -> (GUI#win.options)#options.prog; +radiobutton(GUI, linear) -> (GUI#win.options)#options.linear. + +%% Display load +%% Used when load information is received from the displayed node +-define(highloadfg, {255,99,71}). +-define(midloadfg, yellow). +-define(lowloadfg, green). +-define(highloadbg, {140,157,178}). +-define(midloadbg, ?highloadbg). +-define(lowloadbg, ?highloadbg). + +display_load(GUI, {Old, New}) -> + if + Old == New -> + true; + Old > New -> + leds_down(GUI#win.leds, Old, New); + true -> + leds_up(GUI#win.leds, Old, New) + end. + +leds_down(_Leds, Old, New) when Old == New -> + done; +leds_down(Leds, Old, New) when Old > New -> + reset_led(Leds, Old), + leds_down(Leds, Old-1, New). +leds_up(_Leds, Old, New) when Old == New -> + done; +leds_up(Leds, Old, New) when Old < New -> + set_led(Leds, Old), + leds_up(Leds, Old+1, New). + +led_on_col(N) when N > 13 -> ?highloadfg; +led_on_col(N) when N > 9 -> ?midloadfg; +led_on_col(_) -> ?lowloadfg. + +led_off_col(N) when N > 13 -> ?highloadbg; +led_off_col(N) when N > 9 -> ?midloadbg; +led_off_col(_) -> ?lowloadbg. + +reset_led(_Leds, 0) -> ok; +reset_led(Leds, N) -> + gs:config(lists:nth(N, Leds), [{fill, led_off_col(N)}]). + +set_led(_Leds, 0) -> ok; +set_led(Leds, N) -> + gs:config(lists:nth(N, Leds), [{fill, led_on_col(N)}]). + +%%---------------------------------------------------------------------- +%% Utilities +%%---------------------------------------------------------------------- + +bcast(MNodes, Msg) -> + lists:foreach(fun(MNode) -> + case MNode#mnode.status of + alive -> + MNode#mnode.pid ! Msg; + dead -> + ignore + end + end, + MNodes). + +max(X, Y) when X>Y -> X; +max(_, Y) -> Y. + +%% parse_nodes(MNodes) -> NodeApps +%% MNodes -> [#mnode{}] +%% NodeApps -> [{Node, Status, Apps}] +%% Node -> atom() +%% Status -> alive | dead +%% Apps -> [{Pid, App}] +%% Pid -> pid() +%% App -> atom() +parse_nodes(MNodes) -> + parse_nodes(MNodes, []). +parse_nodes([MNode|MNodes], NodeApps) -> + Apps = parse_apps(MNode#mnode.apps, []), + parse_nodes(MNodes, + [{MNode#mnode.name,MNode#mnode.status,Apps}|NodeApps]); +parse_nodes([], NodeApps) -> + NodeApps. + +parse_apps([{Pid, App, _Descr}|Rest], Apps) -> + parse_apps(Rest, [{Pid, App}|Apps]); +parse_apps([], Apps) -> + Apps. + +%%---------------------------------------------------------------------- +%% Canvas buttons +%%---------------------------------------------------------------------- + +canvasbutton(Canvas, Text, X, Y, W, H, Data) -> + + %% Draw a rectangle (for event catching) + Rect = gs:create(rectangle, Canvas, [{coords, [{X,Y}, {X+W,Y+H}]}, + {fill, gs:read(Canvas, bg)}, + {buttonpress, true}, + {buttonrelease, true}]), + + %% Make the rectangle area look like a 3D button by using lines + Ul = gs:create(line, Canvas, [{coords, [{X,Y+H},{X,Y},{X+W,Y}]}, + {fg, white}, {width, 2}]), + Ll = gs:create(line, Canvas, [{coords, [{X,Y+H},{X+W,Y+H},{X+W,Y}]}, + {fg, {87,87,87}}, {width, 2}]), + + %% Write the text in the middle + Xc = X + round(W/2), + Yc = Y + round(H/2), + T = gs:create(text, Canvas, [{text, Text}, {coords, [{Xc,Yc}]}, + {anchor, c}, + {buttonpress, true}, + {buttonrelease, true}]), + + %% Create the canvasbutton object + CBtn = #canvasbutton{text=T, ul=Ul, ll=Ll, rect=Rect, + x=X, y=Y, w=W, h=H}, + + %% Configure the data + gs:config(T, {data, {canvasbutton, CBtn, Data}}), + gs:config(Rect, {data, {canvasbutton, CBtn, Data}}), + + CBtn. + +press(Canvasbutton) -> + gs:config(Canvasbutton#canvasbutton.ul, {fg, {87,87,87}}), + gs:config(Canvasbutton#canvasbutton.ll, {fg, white}). + +release(Canvasbutton) -> + gs:config(Canvasbutton#canvasbutton.ul, {fg, white}), + gs:config(Canvasbutton#canvasbutton.ll, {fg, {87,87,87}}). diff --git a/lib/appmon/src/appmon_a.erl b/lib/appmon/src/appmon_a.erl new file mode 100644 index 0000000000..b0b5847343 --- /dev/null +++ b/lib/appmon/src/appmon_a.erl @@ -0,0 +1,1117 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(appmon_a). + +%%---------------------------------------------------------------------- +%% +%% Monitors an application, i.e its supervision tree. +%% +%%---------------------------------------------------------------------- +%% +%% +%% INTRODUCTION +%% ------------ +%% +%% This file contains a description of the files involved +%% and the communication between the appmon_a display +%% manager and the appmon_a2 information gatherer. Further +%% information on the placement algorithm can be found in +%% the place.erl file. +%% +%% +%% FILES +%% ----- +%% +%% The supervision tree graphical software consists of +%% the following files: +%% +%% appmon_a Gen server driving the process display window. +%% Responsible for assigning gs identifiers to all +%% processes and process link +%% appmon_a2 The process information gathering routines. +%% Works by following the process links from application +%% master once every second +%% dg The process database is implemented as a shared +%% digraph (see manual pages for digraph) and this is +%% the routines handling this digraph. Since the digraph +%% is shared appmon_a2 will put some info into it that the +%% appmon_a later will modify. The structures used are +%% described in dg.hrl +%% place Places a tree, decides the x and y coordinates (not +%% necessarily corresponding to window coordinates) of +%% processes (or vertices to be specific). Note that +%% special routines are used to transform the possibly +%% cyclic digraph into a strict tree before trying to +%% place it. +%% +%% +%% +%% IMPLEMENTATION DETAIL +%% --------------------- +%% +%% The appmon_a module will follow links between processes, +%% starting with the application master. A unique +%% reference is used to prevent infinite recursion. Note +%% that this process and link gathering is done in the +%% live digraph so that already known processes are +%% updated with the reference and new ones are added to +%% the digraph. After all processes and links have been +%% added or updated a search is made for those processes +%% and links that have an old reference. These are those +%% processes and links that are not present in the +%% application any more. Those are extracted from the +%% digraph and then deleted and the extracts are then +%% used (by appmon_a) to delete the appropriate gs +%% objects. The responsibilities of appmon_a is thus 1) add +%% all new processes and links to the digraph and 2) make +%% a list of all those objects from the digraph that have +%% been deleted. +%% +%% When appmon_a2 has gathered all necessary information it +%% notifies the appmon_a display manager. Note that this is +%% implemented as a call (as opposed to a cast) to +%% prevent appmon_a2 from changing the digraph while appmon_a +%% uses it. appmon_a places all processes using the place +%% module. place will place the processes in the x y +%% planes, hopefully in a nice way, re-forming the +%% digraph during the process into a strict tree using +%% some simple heuristics, some links that makes the +%% graph cyclic will be considered secondary and later +%% coloured red. Note that the process links are not +%% placed since their coordinates are those of the +%% processes that they are links between. The place +%% module is only concerned at a fairly high level of +%% abstraction. Currently its x coordinates are used as +%% real coordinates while the y coordinates must be +%% scaled to correct values, thus the x plane is +%% continous and the y plane is disctrete. +%% +%% Having placed processes the new ones are drawn on the +%% display along with all new process links, then all +%% processes and process links are moved to their +%% possibly new positions. The place module is not +%% sensitive to changes in position and therefore has no +%% concept of which nodes will have to be moved. hence +%% all nodes are moved (but most of them probably to the +%% same position as before) +%% +%% +%% +%% +%%---------------------------------------------------------------------- + + + +-export([start/2, start/3, stop/0]). + + +-record(astate, {app, name, client, digraph}). + +-import(lists, [foreach/2]). + +%% gen server stuff +-behaviour(gen_server). +-export([init/1, handle_cast/2, handle_info/2, terminate/2]). +-export([handle_call/3, code_change/3]). + + +-define(APPSPACE, 10). % The space between apps +-define(NODEAREA_H, 90). % The height of a node +-define(BUTTAREA_H, 80). % The button area height +-define(APPBUTT_H, 20). % Height of appl button +-define(EDITORW, 260). + +-define(MAXWIDTH, 800). +-define(MINWIDTH, 382). +-define(MAXHEIGHT, 450). +-define(MINHEIGHT, 325). + +-define(SUPVIEWTXT, "Sup. view"). +-define(PROCVIEWTXT, "Proc. view"). +-define(CLOSETXT, "Close"). +-define(REFRESHTXT, "Refresh"). +-define(SAVEOPTSTXT, "Save options"). +-define(HELPTXT, "Help"). + +-define(CHARWIDTH, 7). %Should use GS primitives + +-define( darkkhaki, {189, 183, 107}). +-define( palegoldenrod, {238, 232, 170}). +-define( peachpuff4, {139, 119, 101}). +-define( red, red). +-define( darkgrey, {169, 169, 169}). +-define( lightgrey, {211, 211, 211}). +-define( royalblue, {65, 105, 225}). +-define( aquamarine4, {69, 139, 116}). +-define( palegreen4, {84, 139, 84}). +-define( darkseagreen, {105, 139, 105}). +-define( f_line_col, {150, 150, 255}). + + +-include("appmon_dg.hrl"). + + +%%------------------------------------------------------------ +%%------------------------------------------------------------ + + +start(NodeName, AppName) -> + gen_server:start_link(?MODULE, {NodeName, AppName, AppName}, []). + +start(NodeName, AppName, AppId) -> + gen_server:start_link(?MODULE, {NodeName, AppName, AppId}, []). + + +stop() -> + ok. + + + +%%------------------------------------------------------------ +%% Public interface + + +%%------------------------------------------------------------ +%% Administration + +%% AppName is the name of the application, usually an atom like sasl +%% or kernel, AppId is the application pid or the application name, +%% either goes. +init({NodeName, AppName, AppId}) -> + process_flag(trap_exit, true), + {ok, Client} = appmon_info:start_link(NodeName, self(), []), + init_ref(), + init_foreign_places(), + DG = digraph:new([cyclic, private]), + State = #astate{app=AppId, name=AppName, client=Client, digraph=DG}, + refresh(State), + setup_base_win(NodeName, AppName), + {ok, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_call(norequest, _From, State) -> + {reply, null, State}. + +%%------------------------------------------------------------ +%% handle casts + +handle_cast({ping, _Node, _From}, State) -> + {noreply, State}; +handle_cast(_Other, State) -> + {noreply, State}. + + + +%%------------------------------------------------------------ +%% handle info + +handle_info({gs, _, click, _, [?CLOSETXT|_]}, State) -> + {stop, normal, State}; +handle_info({gs, _, destroy, _, _}, State) -> + {stop, normal, State}; +handle_info({gs, _, click, _, [?REFRESHTXT|_]}, State) -> + refresh(State), + {noreply, State}; +handle_info({gs, _, click, _, [?HELPTXT|_]}, State) -> + HelpFile = filename:join([code:lib_dir(appmon), + "doc", "html", "part_frame.html"]), + tool_utils:open_help(win(), HelpFile), + {noreply, State}; +handle_info({gs, Id, click, {mode, Mode}, _}, State) -> + %%io:format("handle_info: Setting mode: ~p~n", [Mode]), + set_mode(Id, Mode), + {noreply, State}; +handle_info({gs, _, click, _, [?SUPVIEWTXT|_]}, State) -> + refresh(State, [{info_type, sup}]), + {noreply, State}; +handle_info({gs, _, click, _, [?PROCVIEWTXT|_]}, State) -> + refresh(State, [{info_type, link}]), + {noreply, State}; +handle_info({gs, Id, buttonpress, _,[1, X, Y|_]}, State) -> + %%io:format("Id clicked: ~p~n", [gs:read(Id, {find, {X, Y}})]), + catch find_pid(State, Id, X, Y), + set_default_mode(), + {noreply, State}; +handle_info({gs, Win, configure, _Data, [W, H|_]}, State) -> + case win() of Win -> user_driven_resize(W, H); + _-> ok + end, + {noreply, State}; + +handle_info({delivery, _S, pinfo, _N, Res}, State) -> + appmon_txt:print(Res), + {noreply, State}; +handle_info({delivery, S, app, N, Res}, State) -> + {delivery, _Serv, app, _Name, {Root, Vs, Ls, SecLs}} = + flush({delivery, S, app, N, Res}), + update2(Vs, Root, Ls, SecLs, State), + {noreply, State}; + +handle_info({kill}, State) -> + {stop, normal, State}; +handle_info({state}, State) -> + {noreply, State}; +handle_info({'EXIT', _Pid, _Reason}, State) -> + {noreply, State}; +handle_info(_Other, State) -> + {noreply, State}. + + +%% Refresh sets new options for the request and forces an update of +%% the screen ant status. +refresh(State) -> + refresh(State, []). +refresh(State, Opts) -> + appmon_info:app(State#astate.client, + State#astate.name, true, Opts). + + + +%% find_pid finds the pid of the clicked object. The scenario is that +%% the user clicks on an item in his window, that ObjId is searched +%% for among all nodes (vertices) and if found action is taken +%% depending on the current mode (see handle_info) +find_pid(State, Id, X, Y) -> + %% Try to manage both versions of GS, remove first case later. + ObjList = case gs:read(Id, {find, {X, Y}}) of + {error, _} -> + gs:read(Id, {hit, {X, Y}}); % Try new format + Num when is_integer(Num) -> [Num]; + _Other -> [] + end, + DG = State#astate.digraph, + All = appmon_dg:get(all, DG), + find_pid2(ObjList, All, DG, State). + +find_pid2([Id | Ids], All, DG, State) -> + case search_for_pid(All, DG, Id) of + {ok, _KeyStr, Pid} -> + handle_proc_press(mode(), Pid, State); + _ -> find_pid2(Ids, All, DG, State) + end; +find_pid2([], _All, _DG, _State) -> ok. + +search_for_pid([V|Vs], DG, ObjId) -> + VD = appmon_dg:get(data, DG, V), + if ObjId==VD#vdata.txt_obj -> + {ok, V, VD#vdata.type}; + true -> search_for_pid(Vs, DG, ObjId) + end; +search_for_pid([], _DG, _ObjId) -> false. + + +%% +%% called when a process has been clicked on. +%% +handle_proc_press(info, Pid, State) -> + appmon_info:pinfo(State#astate.client, Pid, true, + [{timeout, at_most_once}]); +handle_proc_press(send, Pid, _State) -> + {P, RawStr} = two_entries(winroot(), 250, 70, + "Send", "To: ", "Msg: ", + pid_to_list(Pid), "", bg()), + Str = case lists:last(RawStr) of + 46 -> RawStr; + _ -> RawStr++"." + end, + case erl_scan:string(Str) of + {ok, Tokens, _} -> + case erl_parse:parse_term(Tokens) of + {ok, Term} -> + case catch list_to_pid(P) of + To when is_pid(To) -> To ! Term; + _ -> error + end; + _Error -> error + end; + _Error -> error + end; +handle_proc_press(trace, Pid, _State) -> + case trace_state(Pid) of + true -> + io:format("Removing trace on ~p~n", [Pid]), + sys:trace(Pid, false), + set_trace_state(Pid, false); + _Other -> + io:format("Putting trace on ~p~n", [Pid]), + sys:trace(Pid, true, 1000), + set_trace_state(Pid, true) + end; +handle_proc_press(kill, Pid, _State) -> + exit(Pid, kill). + + +trace_state(Pid) -> get({trace_state, Pid}). +set_trace_state(Pid, State) -> put({trace_state, Pid}, State). + +set_default_mode() -> + {Id, Mode} = get(default_mode), + case mode() of + Mode -> true; + _Other -> set_mode(Id, Mode) + end. +set_default_mode(Id, Mode) -> + put(default_mode, {Id, Mode}), + select(Id), %Dirty workaround + set_default_mode(). + +set_mode(Id, Mode) -> + %%io:format("mode=~p~n", [Mode]), + set_mode(Mode), + deselect(), + select(Id). + +set_mode(Mode) -> put(mode, Mode). +mode() -> get(mode). + +flush({delivery, S, A, N, R}) -> + receive + {delivery, S, A, N, R2} -> + flush({delivery, S, A, N, R2}) + after 0 -> + {delivery, S, A, N, R} + end. + + +%%------------------------------------------------------------ +%% Real stuff +%% +update2(Vs, Root, Ls, SecLs, State) -> + DG = State#astate.digraph, + Ref = mk_ref(), + Added = add_procs(Vs, DG, Ref), + AddedLs = add_links(Ls, DG, Ref, primary), + AddedLs2 = add_links(SecLs, DG, Ref, secondary), + DelLs = del_links(appmon_dg:eget(all, DG), DG, Ref), + Dels = del_procs(appmon_dg:get(all, DG), DG, Ref), + + LastX = appmon_place:place(DG, Root), + Width = lists:max(LastX), + Height = length(LastX), + + %% Delete things from screen + del(Dels), del(DelLs), + + %% Add vertices to screen + foreach(fun(V) -> draw_node(DG, V) end, Added), + + %% Add edges to screen + foreach(fun(E) -> draw_edge(DG, E) end, AddedLs), + foreach(fun(E) -> draw_edge(DG, E) end, AddedLs2), + + %% Move vertices on screen + foreach(fun(V) -> move_vertex(DG, V) end, appmon_dg:get(all, DG)), + + tree_driven_resize(Width, Height), + + gs:config(win(), {map, true}), %Make win visible + ok. + +%% Make an integer reference, could have used make_ref BIF but didn't +mk_ref() -> put(reference, get(reference)+1). +init_ref() -> put(reference, 0). + + +%% Add processes (vertices) to digraph, use the string repr of pid as +%% key in digraph. +add_procs([{Pid, Str}|Vs], DG, Ref) -> + case appmon_dg:add(DG, Str, mk_vdata(Str, Pid, Ref), Ref) of + known -> add_procs(Vs, DG, Ref); + updated -> add_procs(Vs, DG, Ref); + _ -> + case lists:member(32, Str) of + true -> + appmon_dg:set(x, DG, Str, foreign), % UNHOLY! + add_procs(Vs, DG, Ref); % Don't add foreign + _ -> [Str | add_procs(Vs, DG, Ref)] + end + end; +add_procs([], _DG, _Ref) -> []. + + +%% Add links to digraph. NOTE that foreign links get a special weight +%% and that no link is added if it goes to a process not in the set of +%% vertices. +%% +%% OTP-1970: Check that linked-to processes really exist. +%% +add_links([{V1, V2}|Ls], DG, Ref, Weight) -> + L = case lists:member(32, V2) of + true -> {V1, V2, foreign}; + _ -> {V1, V2, Weight} + end, + case appmon_dg:get(data, DG, V2) of + false -> add_links(Ls, DG, Ref, Weight); + VD -> + if VD#vdata.ref == Ref -> % OTP-1970 + case appmon_dg:eadd(DG, L, mk_edata(L, Ref), Ref) of + known -> add_links(Ls, DG, Ref, Weight); + updated -> add_links(Ls, DG, Ref, Weight); + _Other -> [L | add_links(Ls, DG, Ref, Weight)] + end; + true -> + add_links(Ls, DG, Ref, Weight) + end + end; +add_links([], _DG, _Ref, _Weight) -> []. + +%% Make an edge data structure +mk_edata(_L, Ref) -> + #edata{ref=Ref}. + +%% Make a vertex data structure, note that pid can be either a pid or +%% a port, we're not picky here. +mk_vdata(P, Pid, Ref) -> + #vdata{ref=Ref, type=Pid, txt=P, width=width(P)}. +width(Txt) -> ?CHARWIDTH*length(Txt)+10. % Should use GS stuff instead + + +%% Delete those processes that have the wrong reference from the +%% digraph. Returns a list of deleted procs and their data (to be able +%% to erase things on screen). +del_procs([V|Vs], DG, Ref) -> + VD = appmon_dg:get(data, DG, V), + if VD#vdata.ref /= Ref -> appmon_dg:del(DG, V), + [{V, VD} | del_procs(Vs, DG, Ref)]; + true -> del_procs(Vs, DG, Ref) + end; +del_procs([], _DG, _Ref) -> []. + + +%% Deletes links that have the wrong reference from the digraph, note +%% that the weight of the edge is not considered here. Returns a list +%% of deleted links and their data (to be able to erase things on +%% screen). +del_links([L | Ls], DG, Ref) -> + ED = appmon_dg:eget(data, DG, L), + if ED#edata.ref /= Ref -> appmon_dg:edel(DG, L), + [{L, ED} | del_links(Ls, DG, Ref)]; + true -> del_links(Ls, DG, Ref) + end; +del_links([], _DG, _Ref) -> []. + +%% Del deletes the GS objects of the list of should-be-deleted +%% items. Returns nothing particular. +del(L) -> + lists:foreach(fun({{V1, V2, Weight}, D}) when is_record(D, edata) -> + if Weight== foreign -> + dealloc_foreign({V1, V2, Weight}); + true -> ok end, + destroy(D#edata.line); + ({_I, D}) when is_record(D, vdata) -> + destroy(D#vdata.sym_obj), + destroy(D#vdata.txt_obj) + end, L). + + +move_vertex(DG, V) -> + VData = appmon_dg:get(data, DG, V), +%% io:format("Vertex ~p data: x:~p, oldx:~p, y:~p, oldy:~p offs:~p~n", +%% [V, VData#vdata.x, VData#vdata.origx, +%% VData#vdata.y, VData#vdata.origy, offsetx()]), + if VData#vdata.x == foreign -> ok; + true -> + X = VData#vdata.x, + Y = scaley(VData#vdata.y), + OldX = VData#vdata.origx, + OldY = scaley(VData#vdata.origy), + if X==OldX, Y==OldY -> true; + true -> + %%io:format("Moving vertex: ~p~n", [V]), + + W = VData#vdata.width, + {BoxC, TxtC} = calc_box_coords(X, Y, W), + + %% move the symbol and text + gs:config(VData#vdata.sym_obj, [{coords, BoxC}]), + gs:config(VData#vdata.txt_obj, [{coords, TxtC}]), + foreach(fun(E) -> move_edge(DG, E) end, + appmon_dg:get(edges, DG, V)) + end + end. + + +move_edge(DG, E) -> + {{V1, V2, Weight}, V1, V2, ED} = appmon_dg:eget(edge, DG, E), + VD1 = appmon_dg:get(data, DG, V1), + VD2 = appmon_dg:get(data, DG, V2), + Line = ED#edata.line, + move_line(DG, VD1, VD2, Line, Weight). +move_line(DG, VD1, VD2, Line, Weight) when is_list(Line) -> + move_line(DG, VD1, VD2, hd(Line), Weight); +move_line(_DG, VD1, VD2, Line, Weight) -> + Coords = calc_coords(VD1, VD2, Weight), + gs:config(Line, [{coords, Coords} | line_opts(Weight)]). + +%% Draw the vertex on the canvas +draw_node(DG, V) -> + %%io:format("Drawing~n",[]), + Data = appmon_dg:get(data, DG, V), + + X = Data#vdata.x, + Y = scaley(Data#vdata.y), + + {Sym, Txt} = draw(rectangle, sup_col(), Data#vdata.txt, X, Y, + Data#vdata.width), + + appmon_dg:av(DG, V, Data#vdata{sym_obj=Sym, txt_obj=Txt}), + true. + +%% Draws a symbol (rectangle for instance) on the canvas. +draw(Symbol, Col, Txt, X, Y, W) -> + {BoxC, TxtC} = calc_box_coords(X, Y, W), + Box = gs:create(Symbol, canvas(), [{coords, BoxC}, {fill, Col}]), + + TxtObj = gs:create(text, canvas(), [{coords, TxtC}, + {anchor, c}, + %%{buttonpress, true}, + {text, Txt}]), + {Box, TxtObj}. + +%% Returns {BoxCoords, TextCoords} +calc_box_coords(X, Y, W) -> + {[{X, Y-radius()}, {X+W, Y+radius()}], [{X+trunc(W/2), Y}]}. + + +%% Draw a line on the canvas +draw_edge(DG, E) -> + {V1, V2, Weight} = E, + Line = draw_line(DG, V1, V2, Weight), +%% io:format("Line: ~p~n", [Line]), + appmon_dg:eset(line, DG, E, Line). + + +%% From is parent, To is child. If To is not a record then we are +%% dealing with a link to a process on another node. Find a suitable +%% place at the left margin and write the process name there and draw +%% a line to it. +%% +draw_line(DG, From, To, foreign) -> + VD1 = appmon_dg:get(data, DG, From), + Y = find_foreign_place(VD1#vdata.y+0.5, foreign_places()), + add_foreign_place({From, To, foreign}, Y), +%% io:format("New Y: ~p~n", [Y]), + appmon_dg:set(x, DG, To, 0), + appmon_dg:set(y, DG, To, Y), + VD2 = appmon_dg:get(data, DG, To), + Coords = calc_coords(VD1, VD2, foreign), +%% io:format("Node coords: ~p~n", [Coords]), + L = gs:create(line, canvas(), [{coords, Coords} | line_opts(foreign)]), + T = gs:create(text, canvas(), [{coords, [{0, 5+scaley(Y)}]}, + {anchor, nw}, {fg, f_line_col()}, +%% {font, {screen, 10}}, + {text, To}]), + [L, T]; + +draw_line(DG, From, To, Weight) -> + VD1 = appmon_dg:get(data, DG, From), + VD2 = appmon_dg:get(data, DG, To), + Coords = calc_coords(VD1, VD2, Weight), + gs:create(line, canvas(), [{coords, Coords} | line_opts(Weight)]). + +%%---------------------------------------------------------------------- +%% +%% Line coordinate calculation +%% +%% Calculate coordinates for edges (links, lines). Primaries have a +%% nice knee and secondaries are oriented differently. If weight is +%% foreign then we will calculate a nice line to the left margin. +%% +calc_coords(From, To, foreign) -> + Y = scaley(To#vdata.y), + X1 = From#vdata.x+trunc(From#vdata.width/2), + Y1 = scaley(From#vdata.y)+radius(), + [{0, Y}, {X1-40, Y}, {X1, Y1}]; +calc_coords(From, To, primary) -> + X1 = From#vdata.x+trunc(From#vdata.width/2), + Y1 = scaley(From#vdata.y)+radius(), + + X2 = To#vdata.x+trunc(To#vdata.width/2), + Y2 = scaley(To#vdata.y)-radius(), + + Y3 = trunc((Y1+Y2)/2), + [{X1, Y1}, {X1, Y3}, {X2, Y3}, {X2, Y2}]; + +calc_coords(V1, V2, _Weight) -> + Y1 = scaley(V1#vdata.y), + X1 = V1#vdata.x, + X1w = X1+V1#vdata.width, + Y2 = scaley(V2#vdata.y), + X2 = V2#vdata.x, + X2w = X2+V2#vdata.width, + + if Y1 == Y2 -> calc_u(X1, X1w, Y1, X2, X2w); + X1w < X2 -> calc_s(X1w, Y1, X2, Y2); + X2w < X1 -> calc_s(X1, Y1, X2w, Y2); + true -> + D1 = abs(X1-X2), D2 = abs(X1w-X2w), + if D1 > D2 -> calc_rbrack(X1w, Y1, X2w, Y2); + true -> calc_lbrack(X1, Y1, X2, Y2) + end + end. + +%% Calculates line coordinates that will go from bottom of one node to +%% bottom of another on the same level. The line will form a nice "U". +calc_u(X1, X1w, Y, X2, X2w) -> + X3 = trunc((X1+X1w)/2), + X4 = trunc((X2+X2w)/2), + Y2 = Y+radius(), + Y3 = Y2+20, + [{X3, Y2}, {X3, Y3}, {X4, Y3}, {X4, Y2}]. + +%% Calculates line coordinates that will go from right (or left) side +%% to right (or left) side, thus forming a "[" or a "]" (bracket). +calc_rbrack(X1, Y1, X2, Y2) -> + X3 = 20 + if X1 > X2 -> X1; + true -> X2 + end, + [{X1, Y1}, {X3, Y1}, {X3, Y2}, {X2, Y2}]. +calc_lbrack(X1, Y1, X2, Y2) -> + X3 = -20 + if X1 < X2 -> X1; + true -> X2 + end, + [{X1, Y1}, {X3, Y1}, {X3, Y2}, {X2, Y2}]. + +%% Calculates line coordinates that will form a nice "S" +calc_s(X1, Y1, X2, Y2) -> + X3 = trunc((X1+X2)/2), + [{X1, Y1}, {X3, Y1}, {X3, Y2}, {X2, Y2}]. + + +%% Options for lines (edges, links) +line_opts(foreign) -> [{width, 2}, {smooth, true}, {fg, f_line_col()}]; +line_opts(primary) -> [{width, 2}, {smooth, false}, {fg, line_col()}]; +line_opts(_) -> [{width, 2}, {smooth, true}, {fg, sec_line_col()}]. + + + +%%---------------------------------------------------------------------- +%% +%% Handling of links to foreign processes +%% +%%---------------------------------------------------------------------- +dealloc_foreign(L) -> +%% io:format("deallocing foreign: ~p~n", [L]), + put(foreign_places, lists:keydelete(L, 1, foreign_places())). +add_foreign_place(V, Y) -> +%% io:format("Adding foreign: ~p~n", [V]), + put(foreign_places, [{V, Y} | foreign_places()]). +foreign_places() -> + get(foreign_places). +init_foreign_places() -> + put(foreign_places, []). + +%% Find a good place for the foreign node +find_foreign_place(StartY, L) -> + case lists:keysearch(StartY, 2, L) of + {value, _} -> find_foreign_place(StartY + 1, L); + _ -> StartY + end. + + +%%------------------------------------------------------------ +%% +%% Graphical stuff +%% + +setup_base_win(NodeName, AppName) -> + set_winroot(gs:start([{kernel,true}])), + + W = ?MINWIDTH, H = ?MINHEIGHT, + + Name = "APPMON: " ++ atom_to_list(AppName) ++ " on " ++ + atom_to_list(NodeName), + + set_win(gs:create(window, winroot(), [{title, Name}, %%{bg, red}, + {x, 250}, {y, 100}, + {width, W}, {bg, win_col()}, + {height, H+?BUTTAREA_H}])), + %% standard buttons + mk_std_butts(win(), W), + set_canvas(gs:create(canvas, win(),[{x,0}, {y,?BUTTAREA_H}, + {width, W}, {height, H}, + {bg, bg()}, + {buttonpress, true}])), + + set_old_win_size(width, gs:read(win(), width)), + set_old_win_size(height, gs:read(win(), height)), + +%% gs:config(win(), {map, true}), %Make win visible + ok. + + +nice_line_coords(W, H) -> + [{0,H-10}, {W,H-10}]. + +%%------------------------------ +%% Button stuff + +mk_butt_area(Win, W) -> + H = ?BUTTAREA_H, + F = gs:create(frame, Win,[{x,0}, {y,0}, %%{bg, frame_col()}, + {width,W}, {height,H}]), + C = gs:create(canvas,F,[{x,0}, {y,0}, {width, W}, {height, H-9}, + {bg, bg()}]), + L = gs:create(line,C,[{coords,nice_line_coords(W, H)}]), + + MB = gs:create(menubar, Win, []), + + FMB = gs:create(menubutton, MB, [{label, {text, "File"}}]), + FM = gs:create(menu, FMB, []), + gs:create(menuitem, FM, [{label, {text, ?CLOSETXT}}]), + + OMB = gs:create(menubutton, MB, [{label, {text, "Options"}}]), + OM = gs:create(menu, OMB, []), + gs:create(menuitem, OM, [{label, {text, ?REFRESHTXT}}]), + Group = now(), + gs:create(menuitem, OM, [{itemtype, separator}]), + gs:create(menuitem, OM, [{label, {text, ?SUPVIEWTXT}}, {itemtype, radio}, + {group, Group}]), + gs:create(menuitem, OM, [{label, {text, ?PROCVIEWTXT}}, {select, true}, + {group, Group}, {itemtype, radio}]), + + HMB = gs:create(menubutton, MB, [{label, {text, "Help"}}, {side, right}]), + HM = gs:create(menu, HMB, []), + gs:create(menuitem, HM, [{label, {text, ?HELPTXT}}]), + + {F, C, L}. + +mk_std_butts(Win, W) -> + {F, C, L} = mk_butt_area(Win, W), + set_bframe(F), set_bcanvas(C), set_bline(L), + + IButt = mk_mode_butt({text, "Info"}, {mode, info}, 10), + mk_mode_butt({text, "Send"}, {mode, send}, 90), + mk_mode_butt({text, "Trace"}, {mode, trace}, 170), + mk_mode_butt({text, "Kill"}, {mode, kill}, 250), + + set_default_mode(IButt, info), + + true. + +select(Id) -> + gs:config(Id, {bg, sel_col()}), + set_selected(Id). + +deselect() -> + gs:config(selected(), {bg, de_sel_col()}). + +mk_mode_butt(Label, Data, X) -> + gs:create(button, bframe(), [{label, Label}, {x, X}, {y, 35}, + {data, Data}, {width, 70}, {height, 25}]). + +%%------------------------------------------------------------ +%% Graphical utilities + +mk_frame(P, X, Y, W, H, BG) -> + gs:create(frame, P, [{x, X}, {y, Y}, {width, W}, {height, H}, {bg, BG}]). + +mk_butt(P, X, Y, W, H, Txt) -> + gs:create(button, P, [{x, X}, {y, Y}, {height, H}, {width, W}, + {label, {text, Txt}}]). + +mk_butt(P, X, Y, Txt) -> + mk_butt(P, X, Y, 70, 20, Txt). + +mk_label(P, X, Y, W, H, Txt, BG) -> + gs:create(label, P, [{x, X}, {y, Y}, {height, H}, {width, W}, + {label, {text, Txt}}, {bg, BG}]). + +mk_entry(P, X, Y, W, H, Txt, BG) -> + gs:create(entry, P, [{x, X}, {y, Y}, {height, H}, {width, W}, {text, Txt}, + {bg, BG}, {keypress, true}]). + + +two_entries(Root, W, H, Name, LTxt1, LTxt2, StartTxt1, StartTxt2, BG) -> + Win = gs:create(window, Root, [{title, Name}, %%{bg, red}, + %%{x, X}, {y, Y}, + {width, W}, {bg, BG}, + {height, H}]), + F = mk_frame(Win, 0, 0, W, H, BG), + + mk_label(F, 10, 10, 30, 20, LTxt1, BG), + mk_label(F, 10, 40, 30, 20, LTxt2, BG), + + E1 = mk_entry(F, 40, 10, 120, 20, StartTxt1, BG), + E2 = mk_entry(F, 40, 40, 120, 20, StartTxt2, BG), + + Ok = mk_butt(F, 170, 10, "Ok"), + Cn = mk_butt(F, 170, 40, "Cancel"), + gs:config(Win, {map, true}), + + Ret = case catch two_entries_loop(E1, E2, Ok, Cn) of + {P2, Msg} -> {P2, Msg}; + _Other -> + false + end, + gs:destroy(Win), + Ret. + + +two_entries_loop(E1, E2, Ok, Cn) -> + receive + {gs, Ok, click, _, _} -> + {gs:read(E1, text), + gs:read(E2, text)}; + {gs, E1, keypress, _, ['Return'|_]} -> + {gs:read(E1, text), + gs:read(E2, text)}; + {gs, E2, keypress, _, ['Return'|_]} -> + {gs:read(E1, text), + gs:read(E2, text)}; + {gs, _, keypress, _, _} -> + two_entries_loop(E1, E2, Ok, Cn); + {gs, Cn, click, _, _} -> + true + end. + +%%-------------------------------------------------------------------- +%% +%% Resizing routines. +%% +%% Resizing deals with a number of different interdependent +%% sizes. Top size is the window size. From window size all other +%% sizes are calculated, we call this the "leader" size. The +%% canvas is usually the same size as the window, except for the +%% row of buttons at the top of the windoww. The canvas is also +%% displaced when the tree is smaller than the minimum window +%% size. +%% +%% +%% Window size - the size of the outer window. Note that +%% provisions must be made for the button area at the top of the +%% window, this is called WinAdj. this is the only item taht +%% changes when the user manually resizes the window. +%% +%% Canvas size - The size of the canvas, should be equal to +%% window size less the button area. Must be adjusted when the +%% window has been manually resized. The canvas also has a +%% scrollregion which must be maintained. Note that we could have +%% used the canvas size as "leading" size, but this did not work +%% since the canvas doesn't fill the complete window when the +%% tree is smaller than the window. +%% +%% Tree size - The size of the tree. This may change whenever a +%% new tree is delivered from the info routine. +%% +%% Dim - All these size adjustments are done in some dimension +%% (width or height). +%% +%% Max, Min - The outmost window may not become larger than Max +%% size or smaller than Min size when resized by the tree +%% size. The user resizing is not restricted to these sizes. +%% +%% Scrollbars: +%% +%% Scrollbars are used whenever necessary, whenever the tree size +%% is bigger than canvas size (in any dimension). +%% +%% Invariants: +%% +%% The three sizes are not varied at the same time. When the +%% window is resized because of a new tree, then window and +%% canvas must be updated. When the user has resized, then only +%% the canvas must be changed (to fit in the window) +%% +%% Tree driven resize +%% +%% This occurs when the tree has been updated. The window may +%% grow and shrink to fit the tree, but may not be smaller than +%% Min and not bigger than Max (scrollbars will be used instead) +%% + +tree_driven_resize(TWidth, THeight) -> + gs:config(win(), {configure, false}), + Width = TWidth+20, + Height = scaley(THeight+1), + put({width, tree}, Width), + put({height, tree}, Height), + adjust_win(width, Width), + adjust_win(height, Height), + fit_tree_to_win(width, Width), + fit_tree_to_win(height, Height), + check_scroll_region(Width, Height, gs:read(canvas(), scrollregion)), + gs:config(win(), {configure, true}), + ok. + + +%% Will adjust the window size to the tree size (given the max and min +%% restrictions. +adjust_win(Dim, TreeSize) -> + case get({Dim, user_resize}) of + true -> ok; + _ -> + WinSize = gs:read(win(), Dim),%%get_dim(Dim, win()), + case get_wanted_winsize(Dim, TreeSize) + winadj(Dim) of + WinSize -> ok; + NewSize -> + %%set(Dim, win(), NewSize+winadj(Dim)) + set_old_win_size(Dim, NewSize), + gs:config(win(), {Dim, NewSize}) + end + end. + +get_wanted_winsize(Dim, Size) -> + Max = maxsize(Dim), Min = minsize(Dim), + if Size > Max -> Max; + Size < Min -> Min; + true -> Size + end. + +set_old_win_size(Dim, Size) -> put({Dim, winsize}, Size). +old_win_size(Dim) -> get({Dim, winsize}). + + +%%-------------------------------------------------------------------- +%% +%% user_driven_resize +%% +%% This is when the user drags the window to some size. This is +%% basically the same as a tree resize, only this time the window +%% itself must not be fiddled with. When the window has been +%% resized this way then normal tree driven resize is not allow +%% to alter the size in that dimension. User overrides. +%% +user_driven_resize(W, H) -> + gs:config(win(), {configure, false}), + check_user_resize(width, W), + check_user_resize(height, H), + check_scroll_region(get({width, tree}), get({height, tree}), + gs:read(canvas(), scrollregion)), + gs:config(win(), {configure, true}). + +check_user_resize(Dim, Size) -> + case old_win_size(Dim) of + Size -> false; + _ -> + put({Dim, user_resize}, true), + set_old_win_size(Dim, Size), + fit_tree_to_win(Dim, get({Dim, tree})) + end. + + + +%%-------------------------------------------------------------------- +%% +%% General resizing routines +%% +%% fit_tree_to_win - Will fit the canvas into a pre-sized window in +%% one dimension. +%% +fit_tree_to_win(Dim, TreeSize) -> + Size = gs:read(win(), Dim) - winadj(Dim), + set_canvas_offset(Dim, Size, TreeSize), + set_button_width(Dim, Size), + if TreeSize > Size -> + gs:config(canvas(), {trans_dim2vh(Dim), trans_dim2enable(Dim)}); + TreeSize < Size -> + gs:config(canvas(), {trans_dim2vh(Dim), false}); + true -> + gs:config(canvas(), {trans_dim2vh(Dim), false}) + end. + + +%%------------------------------ +%% Set the canvas width and displacement in x. +set_canvas_offset(height, Size, _) -> + gs:config(canvas(), {height, Size}); +set_canvas_offset(width, Size, Size) -> + gs:config(canvas(), [{x, 0}, {width, Size}]); +set_canvas_offset(width, Size, TreeSize) when Size<TreeSize -> + gs:config(canvas(), [{x, 0}, {width, Size}]); +set_canvas_offset(width, Size, TreeSize) when Size>TreeSize-> + Val = trunc((Size-TreeSize)/2), + gs:config(canvas(), [{x, Val}, {width, Size-Val}]). + +%%------------------------------ +%% Set the button area width +set_button_width(height,_) -> ok; +set_button_width(width, W) -> + gs:config(bcanvas(), [{width, W}]), + gs:config(bframe(), [{width, W}]), + gs:config(bline(), [{coords, nice_line_coords(W, ?BUTTAREA_H)}]). + + +%%------------------------------ +%% Update the scrollregion size if needed. +check_scroll_region(W, H, {_, _, W, H}) -> ok; +check_scroll_region(W, H, {_, _, _, _}) -> + gs:config(canvas(), {scrollregion, {0, 0, W, H}}). + + +%% Window sizing primitives +winadj(width) -> 0; +winadj(height) -> ?BUTTAREA_H. +maxsize(width) -> ?MAXWIDTH; +maxsize(height) -> ?MAXHEIGHT. +minsize(width) -> ?MINWIDTH; +minsize(height) -> ?MINHEIGHT. + + + +trans_dim2vh(width) -> hscroll; +trans_dim2vh(height) -> vscroll. +trans_dim2enable(width) -> bottom; +trans_dim2enable(height) -> right. + + + + + +%%------------------------------------------------------------ +%% Global Window info + +winroot() -> get(winroot). +win() -> get(win). +canvas() -> get(canvas). +bframe() -> get(bframe). +bcanvas() -> get(bcanvas). +bline() -> get(bline). +set_winroot(X) -> put(winroot, X). +set_win(X) -> put(win, X). +set_canvas(X) -> put(canvas, X). +set_bframe(X) -> put(bframe, X). +set_bcanvas(X) -> put(bcanvas, X). +set_bline(X) -> put(bline, X). + +sup_col() -> ?darkkhaki. +%%work_col() -> ?orange. +bg() -> ?palegoldenrod. +line_col() -> ?peachpuff4. %% saddlebrown.darkgoldenrod +f_line_col() -> ?royalblue. %% saddlebrown.darkgoldenrod +sec_line_col() -> ?red. +win_col() -> bg(). %%darkolivegreen. + +sel_col() -> ?darkgrey. +de_sel_col() -> ?lightgrey. +set_selected(Id)-> put(selected, Id). +selected() -> get(selected). + +scaley(Y) -> 55*Y. +radius() -> 10. + +destroy(undefined) -> true; +destroy(L) when is_list(L) -> lists:foreach(fun(X) -> destroy(X) end , L); +destroy(Win) -> gs:destroy(Win). + diff --git a/lib/appmon/src/appmon_dg.erl b/lib/appmon/src/appmon_dg.erl new file mode 100644 index 0000000000..f53defa946 --- /dev/null +++ b/lib/appmon/src/appmon_dg.erl @@ -0,0 +1,205 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%%------------------------------------------------------------ +%% +%% Digraph handling for process view GUI. Feeble attempt at data +%% separation. Provides functional interface to the data structures +%% vdata and edata, v for vertex and e for edge. +%% +%%------------------------------------------------------------ +-module(appmon_dg). + +-include("appmon_dg.hrl"). + +%% Exports for vertices +-export([get/3, get/2, set/4, av/3, add/4, del/2, visited/3]). + +%% Exports for edges +-export([eget/2, eget/3, eset/4, eadd/4, edel/2, ae/3]). + +%% Exports for convenience +-export([print_dg/1]). + + +%%------------------------------------------------------------ + + +eget(all, DG) -> + digraph:edges(DG). + +eget(data, DG, E) -> + case digraph:edge(DG, E) of + {_, _V1, _V2, Data} -> Data; + _Other -> false + end; +eget(edge, DG, {V1, V2}) -> + case digraph:edge(DG, {V1, V2}) of + {E, W1, W2, ED} -> {E, W1, W2, ED}; + Other -> + case digraph:edge(DG, {V2, V1}) of + {E, W1, W2, ED} -> {E, W1, W2, ED}; + Other -> false + end + end; + +%% Weight in edge name +eget(edge, DG, {V1, V2, Weight}) -> + case digraph:edge(DG, {V1, V2, Weight}) of + {E, W1, W2, ED} -> {E, W1, W2, ED}; + _Other -> false + end; +eget(in, DG, V) -> + efilter(digraph:in_edges(DG, V)). + +efilter(Es) -> + lists:filter(fun({_V1, _V2, primary}) -> true; + (_E) -> false end, + Es). + +eset(ref, DG, E, Ref) -> + {E2, _V1, _V2, D} = eget(edge, DG, E), + update_e(DG, E2, D#edata{ref=Ref}); +eset(line, DG, E, Line) -> + {E2, _V1, _V2, D} = eget(edge, DG, E), + update_e(DG, E2, D#edata{line=Line}). + +edel(DG, E) -> + digraph:del_edge(DG, E). + +eadd(DG, E, D, Ref) -> + case eget(edge, DG, E) of + {_, _, _, ED} when is_record(ED, edata), ED#edata.ref == Ref -> + known; + {_, _, _, ED} when is_record(ED, edata), ED#edata.ref /= Ref -> + update_e(DG, E, ED#edata{ref=Ref}), + updated; + _Other -> + ae(DG, E, D) + end. + +ae(DG, {V1, V2, Weight}, D) -> + digraph:add_edge(DG, {V1, V2, Weight}, V1, V2, D). + +update_e(DG, {V1, V2, Weight}, D) -> + digraph:del_edge(DG, {V1, V2, Weight}), + digraph:add_edge(DG, {V1, V2, Weight}, V1, V2, D). + +%% Filter destination vertex from a list of edges +vfilter(Vs) -> + lists:map(fun({_V1, V2, _Weight}) -> V2; + ({_V1, V2}) -> V2 + end, Vs). + +get(all, DG) -> + digraph:vertices(DG). + +get(data, DG, {V1, V2}) -> + case digraph:edge(DG, {V1, V2}) of + {_,_,_,Data} -> Data; + _Other -> false + end; +get(data, DG, V) -> + case digraph:vertex(DG, V) of + {_,Data} -> Data; + _Other -> false + end; + +%% Return all children of vertex V (those which V has edges to) +get(out, DG, V) -> + vfilter(efilter(digraph:out_edges(DG, V))); +get(in, DG, V) -> + digraph:in_neighbours(DG, V); +get(edges, DG, V) -> + digraph:edges(DG, V); +get(w, DG, V) -> + Data = get(data, DG, V), + Data#vdata.width; +get(x, DG, V) -> + Data = get(data, DG, V), + Data#vdata.x. + +set(type, DG, V, Type) -> + D = get(data, DG, V), + av(DG, V, D#vdata{type=Type}); + +set(ref, DG, V, Ref) -> + D = get(data, DG, V), + av(DG, V, D#vdata{ref=Ref}); + +set(y, DG, V, Y) -> + D = get(data, DG, V), + av(DG, V, D#vdata{y=Y}); + +set(data, DG, V, D) when is_record(D, vdata)-> + av(DG, V, D); + +set(x, DG, V, X) -> + D = get(data, DG, V), + if D#vdata.x /= X -> + av(DG, V, D#vdata{x=X}); + true -> true + end. + +visited(DG, {V1, V2}, Ref) -> % for edge + D = eget(data, DG, {V1, V2}), + if is_record(D, edata), D#edata.ref == Ref -> true; + true -> false + end; +visited(DG, V, Ref) -> + D = get(data, DG, V), + if is_record(D, vdata), D#vdata.ref == Ref -> true; + true -> false + end. + +add(DG, V, D, Ref) -> + case get(data, DG, V) of + D2 when is_record(D2, vdata), D2#vdata.ref==Ref -> + io:format("Ooops in ~p:add vertex~n", [?MODULE]), + known; + D2 when is_record(D2, vdata) -> + %%io:format("~p touch vertex ~p~n", [self(), V]), + set(ref, DG, V, Ref), + set(type, DG, V, D#vdata.type), + save_coords(DG, V), + updated; + _Other -> + av(DG, V, D), added + end. + +save_coords(DG, V) -> + D = get(data, DG, V), + D2 = D#vdata{origx=D#vdata.x, origy=D#vdata.y}, + av(DG, V, D2). + +del(DG, V) -> + digraph:del_vertex(DG, V). + + +av(DG, V, D) -> + digraph:add_vertex(DG, V, D). + +print_dg(DG) -> + io:format("Vertices:~n", []), + lists:foreach(fun(V) -> io:format(" ~p ~p~n", + [V, get(data, DG, V)]) end, + get(all, DG)), + io:format("Edges:~n", []), + lists:foreach(fun(V) -> io:format(" ~p ~p~n", + [V, eget(edge, DG, V)]) end, + eget(all, DG)), + true. diff --git a/lib/appmon/src/appmon_dg.hrl b/lib/appmon/src/appmon_dg.hrl new file mode 100644 index 0000000000..c3485cf1fd --- /dev/null +++ b/lib/appmon/src/appmon_dg.hrl @@ -0,0 +1,45 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + + + +%% +%% The dg package record definitions +%% +%% This is the declarations of the datastructures used for the +%% application monitoring software. All fields are reserved for the +%% implementation except those stated otherwise +%% + +-record(vdata, {ref, % + type, % + x, % + origx=-1, % + y, % + origy=-1, % + txt="", % Set by user + width=0, % Set by user + sym_obj=undefined, % + txt_obj}). % + + + +-record(edata, {ref, % + line, % + weight}). % + diff --git a/lib/appmon/src/appmon_info.erl b/lib/appmon/src/appmon_info.erl new file mode 100644 index 0000000000..4e36d3a13f --- /dev/null +++ b/lib/appmon/src/appmon_info.erl @@ -0,0 +1,963 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%---------------------------------------------------------------------- +%% +%% Information centre for appmon. Must be present on each node +%% monitored. +%% +%% +%% A worklist is maintained that contain all current work that +%% should be performed at each timeout. Each entry in the +%% worklist describes where the result shall be sent and a list +%% of options relevant for that particular task +%% +%% +%% Maintenance Note: +%% +%% This module is supposed to be updated by any who would like to +%% subscribe for information. The idea is that several tools +%% could use this module for their core information gathering +%% services. +%% +%% The module is based on the notion of tasks. Each task should +%% have a nice public interface function which should handle task +%% administration. Tasks are identified by a "key" consisting of +%% three items, the requesting pid, the name of the task and the +%% task auxillary parameter. The requesting pid is the pid of the +%% callee (in the appmon case it can be the node window for +%% instance), the task name is whatever name the task is given +%% (in the appmon case it can be app, app_ctrl or load). The task +%% name can be seen as the type of the task. The task auxillary +%% parameter is an all purpose parameter that have a different +%% meaning for each type of task so in appmon the Aux for app +%% contains the root pid of the monitored application and in +%% app_ctrl it contains the node name (just to distinguish from +%% the other app_ctrl tasks, if any) while the Aux parameter is +%% not used for the load task at all. +%% +%% Each task also carries a list of options for +%% customisation. The options valid for a task is completely +%% internal to that task type except for the timeout option which +%% is used by do_work to determine the interval at which to +%% perform the task. The timeout option may also have the value +%% at_most_once that indicates that the task should not be done +%% more than once, in appmon the remote port (or process) info +%% (pinfo) task is such a task that is only done once for each +%% call. Note that the only way to change or update options is to +%% call the public interface function for the task, this will +%% merge the old options with the new ones and also force the +%% task to be executed. +%% +%% All tasks are managed by the do_work function. The basic +%% functionality being that the result of the task is compared to +%% the previous result and a delivery is sent to the callee if +%% they differ. Most tasks are then done on a regular basis using +%% the timer module for a delay. +%% +%% There are a limited number of places where the module need to +%% be updated when new services are added, they are all marked +%% with "Maintenance Note", and here is a quick guide: +%% +%% First implement the task. Put the functions in this module +%% among the other task implementations. Currently all task +%% implementations should be put in this file to make it simple +%% to monitor a node, this module should be the only one +%% needed. Then add your implementation to the do_work2 function +%% and finally add a public interface function among the other +%% public interface functions. Voila. +%% +%% +%% +%% Future ideas: +%% +%% Appmon should maybe be enhanced to show all processes on a +%% node. First put all processes in an ets P, then pick those +%% that belong to applications (the normal way), then try to find +%% those processes that are roots in process link trees and pick +%% them. The final step would be to do something with those +%% processes that are left. +%% +%%---------------------------------------------------------------------- +-module(appmon_info). +-behaviour(gen_server). + +%% Exported functions +-export([start_link/3, app/4, pinfo/4, load/4, app_ctrl/4]). + +%% For internal use (RPC call) +-export([start_link2/3]). + +%% For debugging +-export([status/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + + +%%---------------------------------------------------------------------- +%% The records +%% +%% state is used for keeping track of all tasks. +%% +%% db is the database used in the app task. +%% + +-record(state, {starter, opts=[], work=[], clients=[]}). +-record(db, {q, p, links, links2}). + + +%%---------------------------------------------------------------------- +%% Macros +%% + +-define(MK_KEY(CMD, AUX, FROM, OPTS), {CMD, AUX, FROM}). +-define(MK_DOIT(KEY), {do_it, KEY}). +-define(ifthen(P,S), if P -> S; true -> ok end). + + +%%---------------------------------------------------------------------- +%% Public interface +%% +%% The Aux parameter is an auxillary parameter that can be used +%% freely by the requesting process, it is included in the work +%% task key. appmon uses it for storing the node name when +%% requesting load and app_ctrl tasks, and appmon_a uses it for +%% storing application name when requesting app task. +%% +%% Maintenance Note: Put new tasks at the end, please. +%% + + +%% Do not use gen_server:start_link because we do not want the +%% appmon_info to die when initiating process dies unless special +%% conditions apply. +%% Uhu, we don't??? Made a fix so that this proces DOES indeed die +%% if it's starter dies. /Gunilla +start_link(Node, Client, Opts) -> + rpc:call(Node, ?MODULE, start_link2, [self(), Client, Opts]). +start_link2(Starter, Client, Opts) -> + Name = {local, ?MODULE}, + Args = {Starter, Opts, Client}, + case gen_server:start(Name, ?MODULE, Args, []) of + {ok, Pid} -> + {ok, Pid}; + {error, {already_started, Pid}} -> + register_client(Pid, Client), + {ok, Pid} + end. + + +%% app_ctrl +%% +%% Monitors which applications exist on a node +%% +app_ctrl(Serv, Aux, OnOff, Opts) -> + gen_server:cast(Serv, {self(), app_ctrl, Aux, OnOff, Opts}). + + +%% load +%% +%% Monitors load on a node +%% +load(Serv, Aux, OnOff, Opts) -> + gen_server:cast(Serv, {self(), load, Aux, OnOff, Opts}). + + +%% app +%% +%% Monitors one application given by name (this ends up in a +%% process tree +%% +app(Serv, AppName, OnOff, Opts) -> + gen_server:cast(Serv, {self(), app, AppName, OnOff, Opts}). + +%% pinfo +%% +%% Process or Port info +%% +pinfo(Serv, Pid, OnOff, Opt) -> + gen_server:cast(Serv, {self(), pinfo, Pid, OnOff, Opt}). + +%% register_client +%% +%% Registers a client (someone subscribing for information) +%% + +register_client(Serv, P) -> + link(Serv), + gen_server:call(Serv, {register_client, P}). + +%% status +%% +%% Status of appmon_info +%% + +status() -> + gen_server:cast(?MODULE, status). + +%%---------------------------------------------------------------------- +%% +%% Gen server administration +%% +%%---------------------------------------------------------------------- + +init({Starter, Opts, Pid}) -> + link(Pid), + process_flag(trap_exit, true), + WorkStore = ets:new(workstore, [set, public]), + {ok, #state{starter=Starter, opts=Opts, work=WorkStore, + clients=[Pid]}}. + +terminate(_Reason, State) -> + ets:delete(State#state.work), + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +%%---------------------------------------------------------------------- +%% +%% Gen server calls +%% +%%---------------------------------------------------------------------- + +handle_call({register_client, Pid}, _From, State) -> + NewState = case lists:member(Pid, State#state.clients) of + true -> State; + _ -> State#state{clients=[Pid | State#state.clients]} + end, + {reply, ok, NewState}; +handle_call(_Other, _From, State) -> + {reply, ok, State}. + +%%---------------------------------------------------------------------- +%% +%% Gen server casts +%% +%%---------------------------------------------------------------------- + +%% Cmd = app_ctrl | load | app | pinfo +handle_cast({From, Cmd, Aux, OnOff, Opts}, State) -> + NewState = update_worklist(Cmd, Aux, From, OnOff, Opts, State), + {noreply, NewState}; +handle_cast(status, State) -> + print_state(State), + {noreply, State}; +handle_cast(_Other, State) -> + {noreply, State}. + + +%%---------------------------------------------------------------------- +%% +%% Gen server info's +%% +%%---------------------------------------------------------------------- + +handle_info({do_it, Key}, State) -> + ok = do_work(Key, State), + {noreply, State}; + +handle_info({'EXIT', Pid, Reason}, State) -> + case State#state.starter of + Pid -> + {stop, Reason, State}; + _Other -> + Work = State#state.work, + del_work(ets:match(Work, {{'$1','$2',Pid}, '_', '_', '_'}), + Pid, Work), + case lists:delete(Pid, State#state.clients) of + [] -> case get_opt(stay_resident, State#state.opts) of + true -> {noreply, State#state{clients=[]}}; + _ -> {stop, normal, State} + end; + NewClients -> {noreply, State#state{clients=NewClients}} + end + end; +handle_info(_Other, State) -> + {noreply, State}. + + +%%---------------------------------------------------------------------- +%% +%% Doing actual work +%% +%%---------------------------------------------------------------------- + +do_work(Key, State) -> + WorkStore = State#state.work, + {Cmd, Aux, From, _OldRef, Old, Opts} = retrieve(WorkStore, Key), + {ok, Result} = do_work2(Cmd, Aux, From, Old, Opts), + if + Result==Old -> ok; + true -> + From ! {delivery, self(), Cmd, Aux, Result} + end, + case get_opt(timeout, Opts) of + at_most_once -> + del_task(Key, WorkStore); + T when is_integer(T) -> + {ok, Ref} = timer:send_after(T, ?MK_DOIT(Key)), + store(WorkStore, Key, Ref, Result, Opts) + end, + ok. + + +%%---------------------------------------------------------------------- +%% +%% Name: do_work2 +%% +%% Maintenance Note: Add a clause here for each new task. +%% +do_work2(load, _Aux, _From, Old, Opts) -> + calc_load(Old, Opts); +do_work2(app_ctrl, _Aux, _From, _Old, _Opts) -> + calc_app_on_node(); +do_work2(app, Aux, _From, _Old, Opts) -> + calc_app_tree(Aux, Opts); +do_work2(pinfo, Aux, _From, _Old, _Opts) -> + calc_pinfo(pinfo, Aux); +do_work2(Cmd, Aux, _From, _Old, _Opts) -> + {Cmd, Aux}. + + +retrieve(Tab, Key) -> + case ets:lookup(Tab, Key) of + [{{Cmd, Aux, From}, Ref, Old, Opts}] -> + {Cmd, Aux, From, Ref, Old, Opts}; + _Other -> + false + end. + +store(Tab, Key, Ref, Old, Opts) -> + ets:insert(Tab, {Key, Ref, Old, Opts}), + Key. + + +%%---------------------------------------------------------------------- +%% +%% WorkStore handling +%% +%%---------------------------------------------------------------------- + +update_worklist(Cmd, Aux, From, true, Opts, State) -> + add_task(Cmd, Aux, From, Opts, State), + State; +update_worklist(Cmd, Aux, From, _Other, _Opts, State) -> + del_task(Cmd, Aux, From, State#state.work), + State. + +%% First check if a task like this already exists and if so cancel its +%% timer and make really sure that no stray do it command will come +%% later. Then start a new timer for the task and store it i +%% WorkStorage +add_task(Cmd, Aux, From, Opts, State) -> + WorkStore = State#state.work, + Key = ?MK_KEY(Cmd, Aux, From, Opts), + OldOpts = del_task(Key, WorkStore), + store(WorkStore, Key, nil, nil, ins_opts(Opts, OldOpts)), + catch do_work(Key, State), + ok. + +%% Delete a list of tasks belonging to a pid +del_work([[Cmd, Aux] | Ws], Pid, Work) -> + del_task(Cmd, Aux, Pid, Work), + del_work(Ws, Pid, Work); +del_work([], _Pid, _Work) -> ok. + +%% Must return old options or empty list +del_task(Cmd, Aux, From, WorkStore) -> + del_task(?MK_KEY(Cmd, Aux, From, []), WorkStore). +del_task(Key, WorkStore) -> + OldStuff = retrieve(WorkStore, Key), + ets:delete(WorkStore, Key), + case OldStuff of + {_Cmd, _Aux, _From, Ref, _Old, Opts} -> + if + Ref /= nil -> + timer:cancel(Ref), + receive + {do_it, Key} -> + Opts + after 10 -> + Opts + end; + true -> Opts + end; + _ -> + [] + end. + + +%% +%% Maintenance Note: +%% +%% Add new task implementations somewhere here below. +%% + + +%%---------------------------------------------------------------------- +%%********************************************************************** +%% +%% +%% BEGIN OF calc_app_tree +%% +%% App tree is the process tree shown in the application window +%% +%% The top (root) pid is found by calling +%% application_controller:get_master(AppName) and this is done in +%% calc_app_on_node (before the call to calc_app_tree). +%% +%% We are going to add processes to the P ets and we are doing it +%% in a two step process. First all prospect processes are put on +%% the queue Q. Then we examine the front of Q and add this +%% process to P if it's not already in P. Then all children of +%% the process is put on the queue Q and the process is repeated. +%% +%% We also maintain two link ets'es, one for primary links and +%% one for secondary links. These databases are updated at the +%% same time as the queue is updated with children. +%% +%%********************************************************************** +%%---------------------------------------------------------------------- + + +calc_app_tree(Name, Opts) -> + Mode = get_opt(info_type, Opts), + case application_controller:get_master(Name) of + Pid when is_pid(Pid) -> + DB = new_db(Mode, Pid), + GL = groupl(Pid), + R = case catch do_find_proc(Mode, DB, GL, find_avoid()) of + {ok, DB2} -> + {ok, {format(Pid), + format(ets:tab2list(DB2#db.p)), + format(ets:tab2list(DB2#db.links)), + format(ets:tab2list(DB2#db.links2))}}; + {error, Reason} -> + {error, Reason}; + Other -> + {error, Other} + end, + ets:delete(DB#db.p), + ets:delete(DB#db.links), + ets:delete(DB#db.links2), + R; + _ -> + {ok, {[], [], [], []}} + end. + +get_pid(P) when is_pid(P) -> P; +get_pid(P) when is_port(P) -> P; +get_pid(X) when is_tuple(X) -> element(2, X). + + +%---------------------------------------------------------------------- +%%--------------------------------------------------------------------- +%% Handling process trees of processses that are linked to each other + +do_find_proc(Mode, DB, GL, Avoid) -> + case get_next(DB) of + {{value, V}, DB2} -> + do_find_proc2(V, Mode, DB2, GL, Avoid); + {empty, DB2} -> + {ok, DB2} + end. + +do_find_proc2(X, Mode, DB, GL, Avoid) when is_port(X) -> + %% There used to be a broken attempt here to handle ports, + %% but the rest of appmon can't handle ports, so now we + %% explicitly ignore ports. + do_find_proc(Mode, DB, GL, Avoid); +do_find_proc2(X, Mode, DB, GL, Avoid) -> + Xpid = get_pid(X), + DB2 = case is_proc(DB, Xpid) of + false -> + add_proc(DB, Xpid), + C1 = find_children(X, Mode), + add_children(C1, Xpid, DB, GL, Avoid, Mode); + _ -> + DB + end, + do_find_proc(Mode, DB2, GL, Avoid). + + +%% Find children finds the children of a process. The method varies +%% with the selected mode (sup or link) and there are also some +%% processes that must be treated differently, notably the application +%% master. +%% +find_children(X, sup) when is_pid(X) -> + %% This is the first (root) process of a supervision tree and it + %% better be a supervisor, we are smoked otherwise + supervisor:which_children(X); +find_children(X, link) when is_pid(X), node(X) /= node() -> + []; +find_children(X, link) when is_pid(X) -> + case process_info(X, links) of + {links, Links} -> + lists:reverse(Links); % OTP-4082 + _ -> [] + end; +find_children({master, X}, sup) -> + case application_master:get_child(X) of + {Pid, _Name} when is_pid(Pid) -> [Pid]; + Pid when is_pid(Pid) -> [Pid] + end; +find_children({_, _X, worker, _}, sup) -> []; +find_children({_, X, supervisor, _}, sup) -> + lists:filter(fun(Thing) -> + Pid = get_pid(Thing), + if + is_pid(Pid) -> true; + true -> false + end + end, + supervisor:which_children(X)). + + +%% Add links to primary (L1) or secondary (L2) sets and return an +%% updated queue. A link is considered secondary if its endpoint is in +%% the queue of un-visited but known processes. +add_children(CList, Paren, DB, _GL, _Avoid, sup) -> + lists:foldr(fun(C, DB2) -> + case get_pid(C) of + P when is_pid(P) -> + add_prim(C, Paren, DB2); + _ -> DB2 end end, + DB, CList); + +add_children(CList, Paren, DB, GL, Avoid, _Mode) -> + lists:foldr(fun(C, DB2) -> + maybe_add_child(C, Paren, DB2, GL, Avoid) + end, DB, CList). + +%% Check if the child is already in P +maybe_add_child(C, Paren, DB, GL, Avoid) -> + case is_proc(DB, C) of + false -> + maybe_add_child_node(C, Paren, DB, GL, Avoid); + _ -> DB % In P: no action + end. + +%% Check if process on this node +maybe_add_child_node(C, Paren, DB, GL, Avoid) -> + if + node(C) /= node() -> + add_foreign(C, Paren, DB); + true -> + maybe_add_child_avoid(C, Paren, DB, GL, Avoid) + end. + +%% Check if child is on the avoid list +maybe_add_child_avoid(C, Paren, DB, GL, Avoid) -> + case lists:member(C, Avoid) of + true -> DB; + false -> + maybe_add_child_port(C, Paren, DB, GL) + end. + +%% Check if it is a port, then it is added +maybe_add_child_port(C, Paren, DB, GL) -> + if + is_port(C) -> + add_prim(C, Paren, DB); + true -> + maybe_add_child_sasl(C, Paren, DB, GL) + end. + +%% Use SASL stuff if present +maybe_add_child_sasl(C, Paren, DB, GL) -> + case check_sasl_ancestor(Paren, C) of + yes -> % Primary + add_prim(C, Paren, DB); + no -> % Secondary + add_sec(C, Paren, DB); + dont_know -> + maybe_add_child_gl(C, Paren, DB, GL) + end. + +%% Check group leader +maybe_add_child_gl(C, Paren, DB, GL) -> + case cmp_groupl(GL, groupl(C)) of + true -> maybe_add_child_sec(C, Paren, DB); + _ -> DB + end. + +%% Check if the link should be a secondary one. Note that this part is +%% pretty much a guess. +maybe_add_child_sec(C, Paren, DB) -> + case is_in_queue(DB, C) of + true -> % Yes, secondary + add_sec(C, Paren, DB); + _ -> % Primary link + add_prim(C, Paren, DB) + end. + +check_sasl_ancestor(Paren, C) -> + case lists:keysearch('$ancestors', 1, + element(2,process_info(C, dictionary))) of + {value, {_, L}} when is_list(L) -> + H = if + is_atom(hd(L)) -> whereis(hd(L)); + true -> hd(L) + end, + if + H == Paren -> yes; + true -> no + end; + _ -> dont_know + end. + + +%---------------------------------------------------------------------- +%%--------------------------------------------------------------------- +%% Primitives for the database DB of all links, processes and the +%% queue of not visited yet processes. + +-define(add_link(C, Paren, L), ets:insert(L, {Paren, C})). + +new_db(Mode, Pid) -> + P = ets:new(processes, [set, public]), + L1 = ets:new(links, [bag, public]), + L2 = ets:new(extralinks, [bag, public]), + Q = if + Mode =:= sup -> queue:in({master, Pid}, queue:new()); + true -> queue:in(Pid, queue:new()) + end, + #db{q=Q, p=P, links=L1, links2=L2}. + +get_next(DB) -> + {X, Q} = queue:out(DB#db.q), + {X, DB#db{q=Q}}. +add_proc(DB, P) -> + ets:insert(DB#db.p, {P}). +add_prim(C, Paren, DB) -> + ?add_link(get_pid(C), Paren, DB#db.links), + DB#db{q=queue:in(C, DB#db.q)}. +add_foreign(C, Paren, DB) -> + ?add_link(C, Paren, DB#db.links2), + DB#db{q=queue:in(C, DB#db.q)}. +add_sec(C, Paren, DB) -> + ?add_link(C, Paren, DB#db.links2), + DB. + +is_proc(#db{p=Tab}, P) -> + ets:member(Tab, P). + +is_in_queue(#db{q=Q}, P) -> + queue:member(P, Q). + +%% Group leader handling. No processes or Links to processes must be +%% added when group leaders differ. Note that catch all is needed +%% because net_sup is undefined when not networked but still present +%% in the kernel_sup child list. Blahh, didn't like that. +groupl(P) -> + case process_info(P, group_leader) of + {group_leader, GL} -> GL; + _Other -> nil + end. + +cmp_groupl(_GL1, nil) -> true; +cmp_groupl(GL1, GL1) -> true; +cmp_groupl(_, _) -> false. + + +%% Do some intelligent guessing as to cut in the tree +find_avoid() -> + lists:foldr(fun(X, Accu) -> + case whereis(X) of + P when is_pid(P) -> + [P|Accu]; + _ -> Accu end end, + [undefined], + [application_controller, init, error_logger, gs, + node_serv, appmon, appmon_a, appmon_info]). + + + +%%---------------------------------------------------------------------- +%% +%% Formats the output strings +%% +%%---------------------------------------------------------------------- +format([{P} | Fs]) -> % Process or port + [{P, format(P)} | format(Fs)]; +format([{P1, P2} | Fs]) -> % Link + [{format(P1), format(P2)} | format(Fs)]; +format([]) -> []; +format(P) when is_pid(P), node(P) /= node() -> + pid_to_list(P) ++ " " ++ atom_to_list(node(P)); +format(P) when is_pid(P) -> + case process_info(P, registered_name) of + {registered_name, Name} -> atom_to_list(Name); + _ -> pid_to_list(P) + end; +format(P) when is_port(P) -> + "port " ++ integer_to_list(element(2, erlang:port_info(P, id))); +format(X) -> + io:format("What: ~p~n", [X]), + "???". + + +%%---------------------------------------------------------------------- +%%********************************************************************** +%% +%% +%% END OF calc_app_tree +%% +%% +%%********************************************************************** +%%---------------------------------------------------------------------- + + + + +%%---------------------------------------------------------------------- +%%********************************************************************** +%% +%% +%% BEGIN OF calc_app_on_node +%% +%% +%%********************************************************************** +%%---------------------------------------------------------------------- + +%% Finds all applications on a node +calc_app_on_node() -> + NewApps = reality_check(application:which_applications()), + {ok, NewApps}. + + +reality_check([E|Es]) -> + N = element(1, E), + case catch application_controller:get_master(N) of + P when is_pid(P) -> [{P, N, E} | reality_check(Es)]; + _ -> reality_check(Es) + end; +reality_check([]) -> []. + + + + +%%---------------------------------------------------------------------- +%%********************************************************************** +%% +%% +%% END OF calc_app_on_node +%% +%% +%%********************************************************************** +%%---------------------------------------------------------------------- + + + +%%---------------------------------------------------------------------- +%%********************************************************************** +%% +%% +%% BEGIN OF calc_load +%% +%% +%%********************************************************************** +%%---------------------------------------------------------------------- + +calc_load(Old, Opts) -> + L = load(Opts), + case get_opt(load_average, Opts) of + true -> + case Old of + {_, L} -> {ok, {L, L}}; + {_, O2} when abs(L-O2) < 3 -> {ok, {O2, L}}; + {_, O2} -> {ok, {O2, trunc((2*L+O2)/3)}}; + _ -> {ok, {0, L}} + end; + _ -> + case Old of + {_, O2} -> {ok, {O2, L}}; + _ -> {ok, {0, L}} + end + end. + + +load(Opts) -> + Q = get_sample(queue), + + case get_opt(load_method, Opts) of + time -> + Td = get_sample(runtime), + Tot = get_sample(tot_time), + + case get_opt(load_scale, Opts) of + linear -> + min(trunc(load_range()*(Td/Tot+Q/6)), + load_range()); + prog -> + min(trunc(load_range()*prog(Td/Tot+Q/6)), + load_range()) + end; + queue -> + case get_opt(load_scale, Opts) of + linear -> + min(trunc(load_range()*Q/6), load_range()); + prog -> + min(trunc(load_range()*prog(Q/6)), load_range()) + end + end. + +min(X,Y) when X<Y -> X; +min(_,Y)->Y. + + +%% +%% T shall be within 0 and 0.9 for this to work correctly +prog(T) -> + math:sqrt(abs(T)/0.9). + + +get_sample(queue) -> statistics(run_queue); +get_sample(runtime) -> {Rt,Rd} = statistics(runtime), + delta(runtime, Rt, Rd); +get_sample(tot_time) -> {Rt,Rd} = statistics(wall_clock), + delta(tot_time, Rt, Rd). + + +%% Keeps track of differences between calls +%% Needed because somebody else might have called +%% statistics/1. +%% +%% Note that due to wrap-arounds, we use a cheating +%% delta which is correct unless somebody else +%% uses statistics/1 +delta(KeyWord, Val, CheatDelta) -> + RetVal = case get(KeyWord) of + undefined -> + Val; + Other -> + if + Other > Val -> + CheatDelta; + true -> + Val-Other + end + end, + put(KeyWord, Val), + RetVal. + + +load_range() -> 16. + + + +%%---------------------------------------------------------------------- +%%********************************************************************** +%% +%% +%% END OF calc_load +%% +%% +%%********************************************************************** +%%---------------------------------------------------------------------- + + +%%---------------------------------------------------------------------- +%%********************************************************************** +%% +%% +%% BEGIN OF calc_pinfo +%% +%% +%%********************************************************************** +%%---------------------------------------------------------------------- + +calc_pinfo(pinfo, Pid) when is_pid(Pid) -> + Info = process_info(Pid), + {ok, io_lib:format("Node: ~p, Process: ~p~n~p~n~n", + [node(), Pid, Info])}; +calc_pinfo(pinfo, Pid) when is_port(Pid) -> + Info = lists:map(fun(Key) ->erlang:port_info(Pid, Key) end, + [id, name, connected, links, input, output]), + + {ok, io_lib:format("Node: ~p, Port: ~p~n~p~n~n", + [node(), element(2, erlang:port_info(Pid, id)), + Info])}; +calc_pinfo(pinfo, _Pid) -> + {ok, ""}. + + +%%---------------------------------------------------------------------- +%%********************************************************************** +%% +%% +%% END OF calc_pinfo +%% +%% +%%********************************************************************** +%%---------------------------------------------------------------------- + + + +%%---------------------------------------------------------------------- +%% +%% Print the State +%% +%% -record(state, {opts=[], work=[], clients=[]}). +%% +%%---------------------------------------------------------------------- +print_state(State) -> + io:format("Status:~n Opts: ~p~n" + "Clients: ~p~n WorkStore:~n", + [State#state.opts, State#state.clients]), + print_work(ets:tab2list(State#state.work)). + +print_work([W|Ws]) -> + io:format(" ~p~n", [W]), print_work(Ws); +print_work([]) -> ok. + + +%%---------------------------------------------------------------------- +%% +%% Option handling +%% +%%---------------------------------------------------------------------- + +%% The only options ever set by a user is info_type, timeout, +%% load_scale and load_method. +get_opt(Name, Opts) -> + case lists:keysearch(Name, 1, Opts) of + {value, Val} -> element(2, Val); + false -> default(Name) + end. + +%% not all options have default values +default(info_type) -> link; +default(load_average) -> true; +default(load_method) -> time; +default(load_scale) -> prog; +default(stay_resident) -> false; +default(timeout) -> 2000. + +ins_opts([Opt | Opts], Opts2) -> + ins_opts(Opts, ins_opt(Opt, Opts2)); +ins_opts([], Opts2) -> Opts2. + +ins_opt({Opt, Val}, [{Opt, _} | Os]) -> [{Opt, Val} | Os]; +ins_opt(Opt, [Opt2 | Os]) -> [Opt2 | ins_opt(Opt, Os)]; +ins_opt(Opt, []) -> [Opt]. diff --git a/lib/appmon/src/appmon_lb.erl b/lib/appmon/src/appmon_lb.erl new file mode 100644 index 0000000000..4e433f37c5 --- /dev/null +++ b/lib/appmon/src/appmon_lb.erl @@ -0,0 +1,689 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +%%% Due to the fact that the application buttons in the appmon window +%%% gets too small to read when the number of applications increases, +%%% this listbox window has been created. +%%% Because of the limitations of GS a listbox was chosen to keep +%%% the nodes and applications. When it's possible to scroll a frame I +%%% think one should put in scrollbars in the appmon main window. +%%% The listbox solution is too slow with lots of applications. +%%% +%%% In the listbox the nodes are shown with their applications beneith. +%%% By double clicking on an application name, or a single click and +%%% then pressing the load button, its application window is started. + +-module(appmon_lb). + +-export ([ + start/1, + stop/1, + add_node/2, + remove_node/2, + add_apps/3, + remove_app/3, + open_win/2, + update_status/3 + ]). + +-export ([init/1]). + +-define (LB_W, 200). % List box width +-define (LB_H, 400). % List box height +-define (BUTT_W, 100). +-define (WIN_W, ?LB_W + ?BUTT_W + 25). % Window width +-define (WIN_H, ?LB_H + 20). % Window height + + +%%% #node{} +%%% +%%% The record 'node' contains the name of the node, its status and +%%% the applications running on that node. +%%% +%%% node == atom () +%%% status == alive || dead +%%% apps == [#app{}] +%%% + +-record (node, {node, %% Name of the node + status = alive, + apps = []}). + +%%% #app{} +%%% +%%% The record 'app' contains the name of the application and its pid +%%% +%%% app == atom () +%%% pid == pid () +%%% + +-record (app, {app, + pid}). + + +%%% #win{} +%%% +%%% The record 'win' contains the pid of the listbox window, +%%% its x and y position, its width and height. +%%% +%%% pid == win_closed || pid () +%%% x == integer () +%%% y == integer () +%%% width == integer () +%%% height == integer () +%%% + +-record (win, {pid = win_closed, + x = 50, + y = 50, + width = ?WIN_W, + height = ?WIN_H}). + + + +%%% Every function in the interface is called with the pid +%%% of this recieve loop, called 'LbPid'. +%%% + + +%%% start /1 +%%% +%%% start returns the pid of the spawned receive loop or +%%% it will call exit/2 after a timeout. +%%% +%%% Pre: +%%% CallingPid == pid () +%%% +%%% Def: +%%% pid () || exit/2 +%%% + +start (CallingPid) -> + PidInit = spawn (?MODULE, init, [CallingPid]), + + %% Wait for a initialization completion message from + %% the spawned process before returning its Pid. + + receive + {initialization_complete, PidInit} -> + PidInit + + %% (Conditional) Failure to start within the time limit + %% will result in termination (Timeout may be infinite). + + after + 60000 -> + exit (PidInit, kill), + exit ({startup_timeout, ?MODULE}) + end. + + + +%%% stop /1 +%%% +%%% stop exits the receive loop +%%% +%%% Post: +%%% exiting the receive loop +%%% + +stop (LbPid) -> + call (LbPid, stop). + + + +%%% add_node /2 +%%% +%%% add_node adds the given node to the DB list. +%%% +%%% Pre: +%%% Node == atom () +%%% +%%% Post: +%%% Node is added to the DB list +%%% + +add_node (LbPid, Node) -> + call (LbPid, {add_node, Node}). + + + +%%% remove_node /2 +%%% +%%% remove_node removes the given node from the DB list. +%%% +%%% Pre: +%%% Node == atom () +%%% +%%% Post: +%%% Node is removed from the DB list +%%% + +remove_node (LbPid, Node) -> + call (LbPid, {remove_node, Node}). + + + +%%% add_apps /3 +%%% +%%% add_apps add the given applications to the given +%%% node in the DB list. +%%% +%%% Pre: +%%% Apps == [App] +%%% App == {Name, Pid} +%%% Name == atom () +%%% Pid == pid () +%%% Node == atom () +%%% +%%% Post: +%%% Node#node{apps = Apps} +%%% + +add_apps (LbPid, Apps, Node) -> + call (LbPid, {add_apps, Apps, Node}). + + + +%%% remove_app /3 +%%% +%%% remove_app remove the given application from the +%%% given node in the DB list. +%%% +%%% Pre: +%%% App == atom () +%%% Node == atom () +%%% +%%% Def: +%%% Node#node{apps = OldApps - App} +%%% + +remove_app (LbPid, App, Node) -> + call (LbPid, {remove_app, App, Node}). + + + +%%% open_win /3 +%%% +%%% open_win opens the listbox window with the given nodes +%%% and their applications. +%%% +%%% Pre: +%%% Nodes_apps == [{Node, Status, Apps}] +%%% Node == atom () +%%% Status == alive || dead +%%% Apps == [App] +%%% App == {AppName, AppPid} +%%% AppName == atom () +%%% AppPid == pid () +%%% +%%% Post: +%%% Window with listbox +%%% + +open_win (LbPid, Nodes_apps) -> + call (LbPid, {open_win, Nodes_apps}). + + + +%%% update_status /3 +%%% +%%% update_status changes the status for the given node. +%%% +%%% Pre: +%%% Node == atom () +%%% Status == alive || dead +%%% +%%% Def: +%%% Node#node{status = Status} +%%% + +update_status (LbPid, Node, Status) -> + call (LbPid, {update_status, Node, Status}). + + + +%%% call /2 +%%% +%%% call sends the given action to the listbox receive loop. +%%% +%%% Pre: +%%% Action == atom () || tuple () +%%% + +call (LbPid, Action) -> + LbPid ! Action. + + + +%%% init /1 +%%% + +init (CallingPid) -> + CallingPid ! {initialization_complete, self ()}, + loop (#win{}, []). + + + +%%% loop /2 +%%% +%%% loop is the recive loop for the listbox window process. +%%% +%%% Pre: +%%% Win == #win{} +%%% Data == [#node{}] +%%% + +loop (Win, Data) -> + receive + {add_node, Node} -> + NewData = add_node_1 (Node, Data), + update (NewData, Win#win.pid), + loop (Win, NewData); + + {remove_node, Node} -> + NewData = dead_node (Node, Data), + update (NewData, Win#win.pid), + loop (Win, NewData); + + {add_apps, Apps, Node} -> + NewData = add_apps_1 (Apps, Node, Data), + update (NewData, Win#win.pid), + loop (Win, NewData); + + {remove_app, App, Node} -> + NewData = remove_app_1 (App, Node, Data), + update (NewData, Win#win.pid), + loop (Win, NewData); + + {open_win, Nodes_apps} -> + NewData = parse_data ([], Nodes_apps), + NewWin = Win#win{pid = init_win ({Win#win.x, Win#win.y})}, + update (NewData, NewWin#win.pid), + loop (NewWin, NewData); + + {update_status, Node, Status} -> + NewData = update_status_1 (Node, Status, Data), + update (NewData, Win#win.pid), + loop (Win, NewData); + + stop -> + true; + + + {gs, _Id, destroy, _D, _Arg} -> + bye; + + {gs, _Id, configure, _D, [W, H | _]} -> + NewWin = configure (Win#win.pid, W, H), + loop (NewWin, Data); + + {gs, lb, doubleclick, _, _Txt} -> + load_app (gs:read (lb, selection), Data), + loop (Win, Data); + + {gs, lb, click, _, _Txt} -> + loop (Win, Data); + + {gs, close, click, _D, _Arg} -> + case Win#win.pid of + win_closed -> + true; + + _opened -> + gs:destroy (Win#win.pid) + end, + loop (#win{}, Data); + + {gs, load, click, _D, _Txt} -> + load_app (gs:read (lb, selection), Data), + loop (Win, Data); + + {gs, clear, click, _D, _Txt} -> + gs:config (lb, {selection, clear}), + loop (Win, Data); + + + _ -> + loop (Win, Data) + end. + + + +%%% init_win /1 +%%% + +init_win ({X, Y}) -> + GS = gs:start (), + + Win = gs:window (win, GS, [{x, X}, + {y, Y}, + {width, ?WIN_W}, + {height, ?WIN_H}, + {title,"Appmon: nodes and applications"}, + {configure, true}]), + + gs:listbox (lb, Win, [{x, 5}, + {y, 10}, + {width, ?LB_W}, + {height, ?LB_H}, + {vscroll, right}, + {hscroll, bottom}, + {selectmode, single}, + {click, true}, + {doubleclick, true}]), + + gs:button (load, Win, [{x, ?WIN_W - ?BUTT_W - 10}, + {y, ?WIN_H - 120}, + {width, ?BUTT_W}, + {label, {text, "Load"}}]), + + gs:button (clear, Win, [{x, ?WIN_W - ?BUTT_W - 10}, + {y, ?WIN_H - 80}, + {width, ?BUTT_W}, + {label, {text, "Clear"}}]), + + gs:button (close, Win, [{x, ?WIN_W - ?BUTT_W - 10}, + {y, ?WIN_H - 40}, + {width, ?BUTT_W}, + {label, {text, "Close"}}]), + + gs:config (Win, {map, true}), + Win. + + + +%%% add_node_1 /2 +%%% +%%% add_node adds the given node in the given window +%%% with its appications in a listbox. +%%% + +add_node_1 (Node, []) -> + [new_node (Node)]; + +add_node_1 (Node, [H | T]) -> + T1 = lists:keysort (#node.node, [new_node (Node) | T]), + [H | T1]. + + + +%%% dead_node /2 +%%% +%%% dead_node returns a list with the given node's +%%% status changed to dead. +%%% + +dead_node (Node, Data) -> + case lists:keysearch (Node, #node.node, Data) of + {value, Node_rec} -> + L = Node_rec#node.apps, + lists:keyreplace (Node, #node.node, + Data, new_node (Node, dead, L)); + + _false -> + Data + end. + + + + + +%%% add_apps_1 /3 +%%% +%%% add_apps_1 returns a list with the given application +%%% into the old list inserted. +%%% + +add_apps_1 (Apps, Node, Data) -> + case lists:keysearch (Node, #node.node, Data) of + {value, _Node_rec} -> + NewApps = parse_apps (Apps, []), + lists:keyreplace (Node, #node.node, + Data, new_node (Node, NewApps)); + + _false -> + Data + end. + + + +%%% remove_app_1 /3 +%%% +%%% remove_app_1 returns a list with the given application +%%% removed from the old list. +%%% + +remove_app_1 (App, Node, Data) -> + + case lists:keysearch (Node, #node.node, Data) of + {value, Node_rec} -> + L = Node_rec#node.apps, + L2 = lists:keydelete (App, #app.app, L), + lists:keyreplace(Node, #node.node, Data, new_node(Node,L2)); + + _false -> + Data + end. + + + +%%% configure /3 +%%% +%%% configure returns a win record after the window has been +%%% configured. +%%% + +configure (WPid, W, H) -> + X = gs:read (WPid, x), + Y = gs:read (WPid, y), + + gs:config (lb, [{width, W - ?BUTT_W - 25}, {height, H - 20}]), + gs:config (load, [{x, W - ?BUTT_W - 10}, {y, H - 120}]), + gs:config (clear, [{x, W - ?BUTT_W - 10}, {y, H - 80}]), + gs:config (close, [{x, W - ?BUTT_W - 10}, {y, H - 40}]), + + #win{pid = WPid, x = X, y = Y, width = W, height = H}. + + + + + +%%% load_app /2 +%%% +%%% load_app opens the application window by calling +%%% the appmon_a module. +%%% + +load_app ([], _Data) -> %% no application chosen + ok; + +load_app ([Index], Data) -> + App = gs:read (lb, {get, Index}), + + case string:substr (App, 1, 3) of + " " -> + AppName = list_to_atom (string:substr (App, 4)), + + case get_node (AppName, Index, Data) of + no_node -> + ok; + + NodeName -> + appmon_a:start (NodeName, AppName) + end; + + _ -> + ok + end. + + + +%%% update_status_1 /3 +%%% +%%% update_status_1 returns a list with the given +%%% node's status updated. +%%% + +update_status_1 (Node, Status, Data) -> + case lists:keysearch (Node, #node.node, Data) of + {value, Node_rec} -> + lists:keyreplace (Node, + #node.node, + Data, + new_node(Node,Status,Node_rec#node.apps)); + + _not_found -> + Data + end. + + + +%%% update /2 +%%% +%%% update updates the listbox with new data. +%%% + +update (_Data, win_closed) -> + true; + +update (Data, _Win) -> + gs:config (lb, clear), + lb_print (Data). + + + +%%% lb_print /1 +%%% +%%% lb_print prints the list into the listbox. +%%% + +lb_print ([]) -> + ok; + +lb_print ([#node{node = Node, status = Status, apps = Apps} | T]) -> + Str = io_lib:format ("~p (~p)", [Node, Status]), + gs:config (lb, {add, Str}), + + case Status of + alive -> + lb_print_apps (Apps); + + _dead -> + gs:config (lb, {add, ""}), + ok + end, + + lb_print (T). + + + +%%% lb_print_apps /1 +%%% +%%% lb_print_apps prints the applications into the listbox. +%%% + +lb_print_apps ([]) -> + ok; + +lb_print_apps ([#app{app = App} | T]) -> + Str = io_lib:format (" ~p", [App]), + gs:config (lb, {add, Str}), + lb_print_apps (T). + + + +%%% new_node /1, 2, 3 +%%% +%%% new_node returna a new node record constructed +%%% with the given data +%%% + +new_node (Node) -> + #node{node = Node}. + +new_node (Node, Apps) -> + #node{node = Node, apps = Apps}. + +new_node (Node, Status, Apps) -> + #node{node = Node, status = Status, apps = Apps}. + + + +%%% new_app /2 +%%% +%%% new_app returns a new application record +%%% constructed with the given data. +%%% + +new_app (App, Pid) -> + #app{app = App, pid = Pid}. + + + +%%% parse_apps /2 +%%% +%%% parse_apps returns a list of application records. +%%% + +parse_apps ([], [H | T]) -> + [H | lists:keysort (#app.app, T)]; + +parse_apps ([App | T], L) -> + Pid = element (1, App), + Name = element (2, App), + parse_apps (T, [new_app (Name, Pid) | L]). + + + +%%% get_node /3 +%%% +%%% get_node returns the node from the given list +%%% or else no_node if it doesn't exists. +%%% + +get_node (_App, _Index, []) -> + no_node; + +get_node (App, Index, [Node | T]) -> + Length = length (Node#node.apps) + 1, + + case Length < Index of + true -> + get_node (App, Index - Length, T); + + false -> + Node#node.node + end. + + + +%%% parse_data /2 +%%% +%%% parse_data returns a list with node records. +%%% + +parse_data (Data, []) -> + Data; + +parse_data (Data, [{Node, Status, Apps} | T]) -> + Apps_1 = parse_apps (Apps, []), + parse_data ([new_node (Node, Status, Apps_1) | Data], T). + + + diff --git a/lib/appmon/src/appmon_place.erl b/lib/appmon/src/appmon_place.erl new file mode 100644 index 0000000000..5a6ae6aa48 --- /dev/null +++ b/lib/appmon/src/appmon_place.erl @@ -0,0 +1,194 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%%------------------------------------------------------------ +%% +%% Places a Digraph in a tree-like manner. The vertices in the digraph +%% is updated with x and y positions. The operation is not atomic. The +%% digraph may be cyclic but edges must then have been labeled primary +%% or secondary and the set of primary links must make up a non-cyclic +%% graph (a tree). +%% +%% +%% IMPLEMENTATION DETAIL +%% --------------------- +%% +%% The placement algorithm is straightforward, place the +%% nodes in the vertical plane (y-plane) and then place +%% nodes in the horisontal plane (x-plane). +%% +%% First all nodes are placed in the y (vertical) plane +%% by a standard traversing of the tree. We then place +%% the tree in the x (horisontal) plane. Each node is +%% placed in the middle of its children as far to the +%% left as possible, preferably at the left margin. Two +%% things can make a node not be placed at the left +%% margin and that is the case when a previous node has +%% been placed at the same vertical level as the node we +%% are trying to place (thus forcing a placement further +%% to the right), and the second case is when the middle +%% of the subtree of the node is not at the left margin +%% (which it only is when the subtree is empty). The +%% algorithm obviously depends on keeping track of the +%% rightmost positions at all depths, and this +%% information is also usefull when calculating the width +%% of the tree. +%% +%% +%% +%%------------------------------------------------------------ + + + +-module(appmon_place). + +-export([place/2]). + +-include("appmon_dg.hrl"). + + +-import(lists, [foreach/2, foldl/3]). + + +place(DG, Root) -> + case appmon_dg:get(data, DG, Root) of + false -> [0]; + _Other -> + placey(DG, Root, 1), + placex(DG, Root, []) + end. + + +%%------------------------------------------------------------ +%% +%% +%% Placing a graph in y plane +%% -------------------------- +%% +%% Place nodes in the graph in the y plane rather stupidly +%% + +placey(DG, V, Y) -> + appmon_dg:set(y, DG, V, Y), + Y1 = Y+1, + foreach(fun(C) -> placey(DG, C, Y1) end, appmon_dg:get(out, DG, V)). + + + + +%%------------------------------------------------------------ +%% +%% +%% Place a tree in the x plane +%% --------------------------- +%% +%% Place nodes in the tree in the x plane. The goal of the x +%% placement is to place all nodes as far to the left as possible +%% while maintaining a nice tree shape. +%% +%% To place a node we must first place its children, the +%% intention is to place the current node in the middle and above +%% its children. The calc_mid function will place the node in the +%% middle of its children. If the node should be placed further +%% to the right than the middle of its children, then its +%% children are moved DeltaX positions to be balanced under the +%% node. Thus at the end the node and its children form a nice +%% looking tree. +%% +%% The function also maintains the 'rightmost x on each level' +%% list LastX by putting its own position on top of the list +%% +%% + +placex(DG, V, LastX) -> + Ch = appmon_dg:get(out, DG, V), + ChLX = foldl(fun(C, Accu) -> placex(DG, C, Accu) end, + tll(LastX), + Ch), + + Width = appmon_dg:get(w, DG, V), + MyX = calc_mid(DG, Width, Ch), + DeltaX = calc_delta(MyX, hdd(LastX)+spacex()), + + appmon_dg:set(x, DG, V, MyX), + move(DG, V, [MyX+Width | ChLX], DeltaX). + + +%%------------------------------------------------------------ +%% +%% +%% Move a subtree DeltaX positions to the right +%% -------------------------------------------- +%% +%% Used when moving children to balance under an already placed +%% parent. Note that the correct LastX depends on the ordering of +%% the children which must be the same as when the children were +%% first placed. It must be ensured that hdd(NewLastX) is the +%% same as hdd(NewLastX)+DeltaX. If the order of children is +%% preserved then so is hdd(LastX). Another solution would be to +%% set hdd(LastX) from the parent +%% +%% Note the two base clauses, one for the no-children case and +%% one optimisation clause (unneccessary perhaps) for DeltaX==0 +%% + +move(_DG, _L, LastX, 0) -> LastX; +move(DG, V, LastX, DeltaX) -> move2(DG, V, LastX, DeltaX). + +move2(DG, V, LastX, DeltaX) -> + NewX = appmon_dg:get(x, DG, V)+DeltaX, + appmon_dg:set(x, DG, V, NewX), + ChLX = foldl(fun(C, LX) -> move2(DG, C, LX, DeltaX) end, + tll(LastX), + appmon_dg:get(out, DG, V)), + [max(NewX+appmon_dg:get(w, DG, V), hdd(LastX)) | ChLX]. + +max(A, B) when A>B -> A; +max(_, B) -> B. + +%%------------------------------------------------------------ +%% +%% +%% Calculate the middle position of the children +%% --------------------------------------------- +%% +%% Calculates the mid x position for a list of children. This +%% position is later compared to the position dictated by LastX +%% in calc_delta. + +calc_mid(_DG, _Width, []) -> 0; +calc_mid(DG, Width, ChList) -> + LeftMostX = appmon_dg:get(x, DG, hd(ChList)), + Z2 = lists:last(ChList), + RightMostX = appmon_dg:get(x, DG, Z2)+appmon_dg:get(w, DG, Z2), + trunc((LeftMostX+RightMostX)/2)-trunc(Width/2). + +calc_delta(Mid, Right) -> + if Right>Mid -> Right-Mid; + true -> 0 + end. + + + +%% Special head and tail +%% Handles empty list in a non-standard way +tll([]) -> []; +tll([_|T]) -> T. +hdd([]) -> 0; +hdd([H|_]) -> H. + +spacex() -> 20. % Should be macro?? diff --git a/lib/appmon/src/appmon_txt.erl b/lib/appmon/src/appmon_txt.erl new file mode 100644 index 0000000000..4e1785c53f --- /dev/null +++ b/lib/appmon/src/appmon_txt.erl @@ -0,0 +1,302 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%%------------------------------------------------------------ +%% +%% Simple text viewer +%% +%%------------------------------------------------------------ + +-module(appmon_txt). +-export([start/0, start/1, print/1, fprint/1]). + +%% gen_server stuff +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2]). + +-define(LOADTXT, "Load file"). +-define(SAVETXT, "Save file"). +-define(SAVEASTXT, "Save as"). +-define(CLOSETXT, "Close"). +-define(HELPTXT, "Help"). + +%%------------------------------------------------------------ +%% +%% start/0 starts an open text viewer that can be filled with +%% whatever. +%% +%%------------------------------------------------------------ +start() -> + start([]). + +%%------------------------------------------------------------ +%% +%% start(ListOfOptions) starts an open text viewer with options +%% +%% Options can be +%% {file, FileName} - insert contents of file +%% locked - the text cannot be edited +%% {text, Text} - insert text at startup +%% +%%------------------------------------------------------------ +start(Opts) -> + gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). + +%% Start a text viewer if necessary +print(Txt) -> + catch start(), + gen_server:call(?MODULE, {add_txt, Txt}), + ok. + +fprint(File) -> + catch start(), + gen_server:call(?MODULE, {add_file, File}), + ok. + + +%%------------------------------------------------------------ +%% gen server admin + +init(Opts) -> + process_flag(trap_exit, true), + setup_base_win(), + default_status(), + setup_opts(Opts), + {ok, []}. + +terminate(_Reason, _State) -> + ok. + +%%------------------------------------------------------------ +%% gen server stuff +handle_call({add_txt, Txt}, _From, State) -> + do_insert_text(Txt), + scroll_to_last_line(), + {reply, ok, State}; +handle_call({add_file, FileName}, _From, State) -> + do_load_file(FileName), + {reply, ok, State}; +handle_call(_Request, _From, State) -> + {reply, ok, State}. +handle_cast(_Request, State) -> + {noreply, State}. +handle_info({gs, _, click, _, [?CLOSETXT|_]}, State) -> + {stop, normal, State}; +handle_info({gs, _, click, _, [?LOADTXT|_]}, State) -> + ui_load(), + {noreply, State}; +handle_info({gs, _, configure, _, [W, H | _]}, State) -> + resize(W, H), + {noreply, State}; + +handle_info({gs, _, destroy, _, _}, State) -> + {stop, normal, State}; +handle_info(Request, State) -> + io:format("~p got info: ~p~n", [self(), Request]), + print_status("Not implemented"), + {noreply, State}. + + +%%------------------------------------------------------------ +%% Handle options + +setup_opts([Opt|Opts]) -> + setup_opt(Opt), + setup_opts(Opts); +setup_opts([]) -> ok. + +setup_opt(Opt) -> + case Opt of + {file, FileName} -> + do_load_file(FileName); + locked -> + do_lock(); + {text, Text} -> + do_insert_text(Text); + _Other -> + ok + end. + +do_load_file(FileName) -> + case catch i_load_file(FileName) of + ok -> + default_status(); + _Other -> + print_status(lists:append(["File not found: ", FileName])) + end. + +i_load_file(FileName) -> + {ok, Bin} = file:read_file(FileName), + L = binary_to_list(Bin), + i_do_clear(), + do_insert_text(L), + ok. + +ui_load() -> + Title = "Load file", + Files = get_file_list(), + case catch ui_list_dialog(Title, "File: ", Files) of + {ok, FileName} -> + do_load_file(FileName); + _Other -> + print_status("Load cancelled") + end. + +get_file_list() -> + case file:list_dir(".") of + {ok, FileList} -> lists:sort(FileList); + _Other -> [] + end. + +do_insert_text(Text) -> + gs:config(editor(), {insert, {'end', Text}}), + ok. + +%% Scrolls editor to show the last rows +scroll_to_last_line() -> + H = gs:read(editor(), size), + R = gs:read(editor(), height), + TopRow = H-R/15, + if TopRow > 0 -> gs:config(editor(), {vscrollpos, TopRow}); + true -> gs:config(editor(), {vscrollpos, 0}) + end, + ok. + +do_lock() -> + gs:config(editor(), {enable, false}). + +i_do_clear() -> + gs:config(editor(), clear). + +%%------------------------------------------------------------ +%% Graphical stuff + +label_h() -> 20. +menu_h() -> 29. + +setup_base_win() -> + H = 400, W=580, + LabelHeight=label_h(), MenuHeight=menu_h(), + + F = gs:start([{kernel,true}]), + set_winroot(F), + + Win = gs:create(window, F, [{width, W}, {height, H}, + {title,"APPMON: Process Information"}]), + + E = gs:create(editor, Win, [{x, 0}, {y, MenuHeight}, + {width, W}, + {height, H-MenuHeight-LabelHeight-1}, + {vscroll, right}]), + set_editor(E), + + L = gs:create(label, Win, [{x, 0}, {y, H-LabelHeight}, + {height,LabelHeight }, {width, W}, + {align, w}]), + set_status(L), + print_status("Loading"), + + gs:config(Win, {map, true}), + + MB = gs:create(menubar, Win, []), + + FMB = gs:create(menubutton, MB, [{label, {text, "File"}}]), + FM = gs:create(menu, FMB, []), + gs:create(menuitem, FM, [{label, {text, ?CLOSETXT}}]), + + gs:config(Win, {configure, true}), + ok. + +resize(W, H) -> + gs:config(editor(), [{width, W}, {height, H-label_h()-menu_h()}]), + gs:config(status(), [{y, H-label_h()}, {width, W}]), + ok. + +%%------------------------------------------------------------ +%% ui_list_dialog( +%% +%% Traditional dialog with a list box and a selection field that +%% is updated from the list box. +%% +%% Returns {ok, String} if successful and something else if not +%% +%% Title - the name of the window +%% LeadText - the lead text on the selection field +%% List - a list of items that will be displayed in the list box +%% +%%------------------------------------------------------------ + +ui_list_dialog(Title, LeadText, TxtList) -> + W = 200, H = 300, + + Win = gs:create(window, winroot(), [{title, Title}, + {width, W},{height, H}]), + Ok = gs:create(button, Win, [{x, 10}, {y,10}, + {width, 50}, {height, 20}, + {label, {text, "Ok"}}]), + Cn = gs:create(button, Win, [{x, 70}, {y,10}, + {width, 50}, {height, 20}, + {label, {text, "Cancel"}}]), + + gs:create(label, Win, [{x, 10}, {y, 50}, + {width, 60}, {height, 20}, + {label, {text, LeadText}}]), + Box = gs:create(entry, Win, [{x, 10}, {y, 70}, + {width, 160}, {height, 20}, + {keypress, true}]), + List = gs:create(listbox, Win, [{x, 10}, {y, 100}, {width, 180}, + {height, 190}, + {items, TxtList}, {vscroll, right}, + {hscroll, false}, {click, true}, + {doubleclick, true}, + {keypress, true}]), + gs:config(Win, {map, true}), + + RetVal = ui_load_loop(Box, List, Ok, Cn), + + gs:destroy(Win), + + RetVal. + +ui_load_loop(Box, List, Ok, Cn) -> + receive + {gs, Box, keypress, _, ['Return'|_]} -> + {ok, gs:read(Box, text)}; + {gs, Box, keypress, _, _} -> + ui_load_loop(Box, List, Ok, Cn); + {gs, Ok, click, _, _} -> + {ok, gs:read(Box, text)}; + {gs, List, doubleclick, _, [_Idx, Txt|_]} -> + {ok, Txt}; + {gs, List, click, _, [_Idx, Txt|_]} -> + gs:config(Box, {text, Txt}), + ui_load_loop(Box, List, Ok, Cn); + _Other -> + something_else + end. + +%% The status row at the bottom of the window +set_status(Id) -> put(status_row, Id). +status() -> get(status_row). +print_status(Msg) -> gs:config(get(status_row), {label, {text, Msg}}). +default_status() -> print_status("Done"). + +set_editor(X) -> put(editor, X). +editor() -> get(editor). + +winroot() -> get(winroot). +set_winroot(X) -> put(winroot, X). diff --git a/lib/appmon/src/appmon_web.erl b/lib/appmon/src/appmon_web.erl new file mode 100644 index 0000000000..e8a8422a80 --- /dev/null +++ b/lib/appmon/src/appmon_web.erl @@ -0,0 +1,1037 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%%--------------------------------------------------------------------- +%%% File : webappmon.erl +%%% Author : Martin G. <[email protected]> +%%% Purpose : Frontend to the webbased version of appmon. +%%% Created : 24 Apr 2001 by Martin G. <[email protected]> +%%%--------------------------------------------------------------------- + +-module(appmon_web). + +%% The functions that the user can call to interact with the genserver +-export([init/1,handle_call/3,handle_cast/2,handle_info/2]). +-export([terminate/2,code_change/3]). + +-export([node_info/2,application_info/2,application_env/2]). +-export([proc_info/2,trace/2]). +-export([start/0,stop/0,start_link/0]). + +%% Export the function that returns the configuration data needed by +%% webtool +-export([configData/0]). + + +%% The following directive caters for (significantly) faster native +%% code compilation of one function in this file by the HiPE compiler +%% on register-poor architectures like the x86. +-compile([{hipe,[{regalloc,graph_color}]}]). + +-behaviour(gen_server). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Start the genserver % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start_link()-> + gen_server:start_link({local,webappmon_server},appmon_web,[],[]). +start()-> + gen_server:start({local,webappmon_server},appmon_web,[],[]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Stop the genserver % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +stop()-> + gen_server:call(webappmon_server,stop,1000). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Get the page that shows the nodes and the apps on the sel node % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +node_info(Env,Input)-> + gen_server:call(webappmon_server,{node_data,Env,Input}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Get the application process tree % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +application_info(Env,Input)-> + gen_server:call(webappmon_server,{app_data,Env,Input}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Get the page that shows the data about the process % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +proc_info(Env,Input)-> + gen_server:call(webappmon_server,{proc_data,Env,Input}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Get the spec on the app % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +application_env(Env,Input)-> + gen_server:call(webappmon_server,{app_env,Env,Input}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Toggle the trace flag for the selected process % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +trace(Env,Input)-> + gen_server:call(webappmon_server,{trace,Env,Input}). + +configData()-> + {appmon,[{web_data,{"WebAppmon","/appmon/main_frame.html"}}, + {alias,{"/appmon",code:priv_dir(appmon)}}, + {alias,{erl_alias,"/erl",[appmon_web]}}, + {start,{child,{backend,{process_info,start_link,[]}, + permanent,100,worker,[process_info]}}}, + {start,{child,{{local,webappmon_server}, + {appmon_web,start_link,[]}, + permanent,100,worker,[appmon_web]}}} + ]}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% Callback functions for the genserver % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +init(_Arg)-> + {ok,[]}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Create the different pages % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +handle_call({node_data,_Env,Input},_From,State)-> + {reply,app_and_node_sel_page(Input),State}; + +handle_call({app_data,_Env,Input},_From,State)-> + {reply,process_tree_page(Input),State}; + +handle_call({proc_data,_Env,Input},_From,State)-> + {reply,process_specifickation_page(Input),State}; + +handle_call({app_env,_Env,Input},_From,State)-> + {reply,application_specifickation_page(Input),State}; + +handle_call({trace,_Env,Input},_From,State)-> + {reply,toggle_trace(Input),State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Shutdown the genserver % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +terminate(_,_State)-> + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Callback function currently not used ... % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +handle_cast(_,State)-> + {noreply,State}. + +handle_info(_,State)-> + {noreply,State}. + +code_change(_OldVsn,State,_Extra)-> + {ok,State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Private functions to create the part of the sides that is common %% +%% to all sides %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Create the Header for the page If we now the mimetype use that type%% +%% otherwise use text %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +header() -> + header("text/html"). +header(MimeType) -> + "Content-type: " ++ MimeType ++ "\r\n\r\n". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Create the Htmlheader sett the title of the side to nothing if %% +%% we dont know the name of the side %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +html_header()-> + html_header(""). + +html_header(Part) -> + "<HTML BGCOLOR=\"#FFFFFF\">\n" ++ + "<HEAD>\n" ++ + "<TITLE>Appmon " ++ Part ++ "</TITLE>\n" ++ + "</HEAD>\n". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Close the Html tag and if neccessay add some clean upp %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +html_end()-> + "</HTML>". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% The functions that creates the whole pages by collecting %% +%% the necessary data %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Returns the page where the user see's which nodes and apps that %% +%% are availible for monitoring %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +app_and_node_sel_page(Input)-> + [header(), + html_header(), + node_body(httpd:parse_query(Input)), + html_end()]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Returns the process tree for the application whose name is %% +%% the first value in the Inputs key/value list %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +process_tree_page(Input)-> + [header(), + html_header(), + application_javascript(httpd:parse_query(Input)), + application_body(httpd:parse_query(Input)), + html_end()]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Send trace on or off to the process thats pid is the third arg of %% +%% the inputs key/val list. Then it returns the process tree for the %% +%% the application that is the first key/val pair of input %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +toggle_trace(Input)-> + send_trace(httpd:parse_query(Input)), + [header(), + html_header(), + application_javascript(httpd:parse_query(Input)), + application_body(httpd:parse_query(Input)), + html_end()]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Creates the page that shows all information about the process that %% +%% that is the first arg of th input key/val pairs %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +process_specifickation_page(Input)-> + [header(), + html_header(), + process_body(httpd:parse_query(Input)), + html_end()]. + +application_specifickation_page(Input)-> + [header(), + html_header(), + application_env_body(httpd:parse_query(Input)), + html_end()]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The Private functions that do the job %% +%% To build the the page that shows the applications %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Build the body of the side that shows the node name and %% +%% the application list %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +node_body([{"node",Node}|_Rest])-> + case process_info:is_node(Node) of + {true,Controlled_node,Name} -> + "<BODY BGCOLOR=\"#FFFFFF\">" ++ + node_selections_javascripts() ++ + node_selection(Controlled_node) ++ + node_title() ++ + application_tree(Controlled_node,Name) ++ + "</BODY>"; + + {false,Server_node,Name} -> + "<BODY BGCOLOR=\"#FFFFFF\">" ++ + node_selections_javascripts() ++ + node_selection(Server_node) ++ + node_title() ++ + application_tree(Server_node,Name) ++ + "</BODY>" + end; + +node_body(_Whatever)-> + node_body([{atom_to_list(node),atom_to_list(node())}]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Returns the javascript that sets a new node to monitor %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +node_selections_javascripts()-> + "<SCRIPT> + function node_selected() + { + parent.frames.base_frames.location=\"../../appmon/start_info.html\" + window.location =\"./node_info?node=\" + " ++ + "document.node_selection.nodes[document.node_selection.nodes.selectedIndex].value; + } + </SCRIPT>". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Insert the html code that shows the combobox where the user can %% +%% select another node to monitor %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +node_selection(Node)-> + " <FORM ACTION=\"./node_info\" NAME=node_selection>\n + <TABLE WIDTH=\"100%\" BORDER=\"0\">\n + <TR><TD ALIGN=\"center\">\n + <SELECT NAME=nodes onChange=\"node_selected()\">\n" ++ + print_nodes(order_nodes(Node,process_info:get_nodes())) ++ + "</SELECT>\n + </TD></TR>\n + </TABLE>\n + </FORM>". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Add the node we are working with in the beginning of the list and %% +%% remove it from other places so its always the first in the listbox %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +order_nodes(Node,Node_list)-> + [Node|lists:delete(Node,Node_list)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Take the list of nodes and make it to a list of options to the %% +%% the combobox %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +print_nodes([])-> + []; +print_nodes([Node|Rest])-> + "<OPTION value=\"" ++ + atom_to_list(Node) ++ + "\">" ++ + atom_to_list(Node) ++ + "\n" ++ + print_nodes(Rest). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Create the header of the node info page i.e. the name of the node %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +node_title()-> + " <TABLE WIDTH=\"100%\" BORDER=\"0\"> + <TR><TD ALIGN=\"center\"><FONT SIZE=5>Applications</FONT></TD></TR> + </TABLE>\n". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Build the body of the side that shows the node i.e the application %% +%% list %% +%% Node and Node_name are the same just different types %% +%% Node are the atom Node_name the string of the node name %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +application_tree(Node,Node_name)-> + Fun=fun(Name)-> + Name_str =atom_to_list(Name), + "<LI><A HREF=\"./application_info?name=" ++ Name_str ++ + "&mode=all&node=" ++ Node_name ++ + "\" TARGET=main><B>" ++ Name_str ++ + "</B></A>" ++ print_space(15-length(Name_str),[]) ++ + "<A HREF=\"./application_env?name=" ++ Name_str ++ + "&node=" ++ Node_name ++ + "\" TARGET=\"main\"><FONT SIZE=2>spec</FONT></A></LI>\n" + end, + "<UL>" ++ + lists:map(Fun, (process_info:get_applications(Node))) ++ + "</UL>" ++ + "<FORM Name=reload>" ++ + "<INPUT TYPE=\"button\" onClick=\"node_selected()\" + VALUE=\"Reload\">\n" ++ + "</FORM>" ++ + "<!--<A HREF=\"../../appmon/application_help.html\" TARGET=main>Help</A>-->". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Print spaces between the application name and the spec link %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +print_space(N,Space)when N >0 -> + print_space(N-1," " ++ Space); +print_space(_N,Space)-> + Space. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The Private functions that do the job %% +%% To build the the page that shows process in an application %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%Generates the javascript that govern the look of the page that %% +%%the processes of an application %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%Args is the list whit input args should be App Mode, Node +application_javascript(Args)when length(Args)>=3 -> + Vars= + "<SCRIPT> + var proc; + var app=\"" ++ element(2,lists:nth(1,Args)) ++ "\"; + var node=\"" ++ element(2,lists:nth(3,Args)) ++ "\";", + CommonFuncs= + " function reload_bottom_frame() + {parent.proc_data.location.href=\"/appmon/blank.html\";} + + function show_process_info() + { + if(proc.indexOf(\"#Port\")== -1) + { + if(proc.charAt(0)==\'<\') + window.location=\"./proc_info?name=\" + proc + \"&node=\" + node + else + { + start=proc.indexOf(\"<\"); + endpoint=proc.lastIndexOf(\">\"); + window.location=\"./proc_info?name=\" + proc.slice(start,endpoint+1) + \"&node=\" + node ; + } + } + } + + function trace() + { + if(proc.charAt(0)==\'<\') + window.location=\"./trace?name=\" + app + \"&mode=\" + get_mode() + \"&node=\" + node + \"&proc=\" + proc; + else + { + start=proc.indexOf(\"<\"); + endpoint=proc.lastIndexOf(\">\"); + window.location=\"./trace?name=\" + app + \"&mode=\" + get_mode() + \"&node=\" + node + \"&proc=\" + + proc.slice(start,endpoint+1) ; + } + + } + + function reload_page()\n + { + window.location=\"./application_info?name=\" + app + \"&mode=\" + get_mode() + \"&node=\" + node ; + } + function get_mode() + { + for (i= 0; i < document.reload_form.mode.length; i++) + { + if (document.reload_form.mode[i].checked) + return(document.reload_form.mode[i].value); + } + return(\"all\"); + }", + Vars++CommonFuncs++"</SCRIPT>"; +application_javascript(_)-> + "<SCRIPT></SCRIPT>". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Create the body i.e the process tree for the applications whose %% +%% name is the second arg in the first tuple %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%args is the list [{_,Appname},{_,Mode},{_Node}] +application_body(Args) when is_list(Args),length(Args) >= 3 -> + App=element(2,lists:nth(1,Args)), + Mode=element(2,lists:nth(2,Args)), + Node=element(2,lists:nth(3,Args)), + "<BODY BGCOLOR=\"FFFFFF\" onLoad=reload_bottom_frame() >" + ++ mode_selection(Mode) ++ + selected_app_header(App,Node) ++ process_tree(App,Mode,Node)++ + "</BODY>"; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% If the pattern above ain't match then something is wrong %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +application_body(_Whatever)-> + "Please use the links to the left". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Create the part of the process tree page side where the user can %% +%% select the mode the view the tree in. %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mode_selection(Mode)-> + "<FORM NAME=\"reload_form\">\n" ++ + "<TABLE>" ++ + "<TR>\n" ++ + "<!--<TD><INPUT TYPE=\"button\" NAME=\"refresh_but\" VALUE=\"Reload\" onClick=\"reload_page()\"> + </TD>\n-->" ++ + print_radio_buttons([{"all","All processes"},{"sup_child","Supervised processes"}, + {"sup","Only supervisors"}],Mode) ++ + "</TR>\n </TABLE>\n" ++ + "</FORM>". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Print the radiobuttons. if the mode is the one the current %% +%% radiobutton represent set the one checked %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +print_radio_buttons([],_)-> + []; +print_radio_buttons([{Mode,Name}|Rest],Mode)-> + "<TD><INPUT TYPE=\"radio\" NAME=\"mode\" CHECKED=\"true\" VALUE=\""++ + Mode ++"\" onClick=\"reload_page()\"> " ++Name ++ + "</TD>\n" ++ print_radio_buttons(Rest,Mode); +print_radio_buttons([{Mode1,Name}|Rest],Mode)-> + "<TD><INPUT TYPE=\"radio\" NAME=\"mode\" VALUE=\""++ Mode1 ++ + "\" onClick=\"reload_page()\"> " ++ Name ++ + "</TD>\n" ++ + print_radio_buttons(Rest,Mode). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The part that shows the name of the application that the process %% +%% tree represent %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +selected_app_header(App,Node)-> + {Year,Mon,Day}=date(), + "<TABLE> + <TR> + <TD>Node:</TD> + <TD>" ++Node ++"</TD> + </TR> + <TR> + <TD>Application:</TD> + <TD>" ++App ++"</TD> + </TR> + <TR> + <TD>Date:</TD> + <TD>" ++ integer_to_list(Day) ++ "/" ++ + integer_to_list(Mon) ++" - "++ + integer_to_list(Year) ++ + "</TD> + </TR> + </TABLE> + <TABLE WIDTH=100%> + <TR> + <TD> + <HR WIDTH=\"80%\"> + <!--<FONT SIZE=4>Process tree</FONT> + <HR ALIGN=\"center\" WIDTH=\"80%\">--> + </TD> + </TR> + </TABLE>". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%get the process tree from process_info and build the nested %% +%% unordered list that represent the applications process tree %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +process_tree(App,Mode,Node)-> + case process_info:get_processes(list_to_atom(App), + list_to_atom(Mode), + list_to_atom(Node)) of + unknown-> + "Unknown application please update application tree"; + {Tree,Traced_dict} -> + "<UL>" ++ + htmlify_tree(Tree,Traced_dict,1,Node,Mode,App) ++ + "</UL>" + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Build each node in the tree and then build its children %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +htmlify_tree({Pid,Childs,Childs2},Proc_tab,N,Node,Mode,App)-> + case ets:lookup(Proc_tab,Pid) of + [] when N<3-> + print_pid(Pid,Node,Mode,App,notrace)++ + htmlify_prim_child(Childs,Proc_tab,N+1,Node,Mode,App) ++ + htmlify_sec_child(Childs2); + [_Traced]-> + print_pid(Pid,Node,Mode,App,"<FONT SIZE=2 COLOR=\"firebrick\">Stop Trace</FONT>")++ + htmlify_prim_child(Childs,Proc_tab,N+1,Node,Mode,App) ++ + htmlify_sec_child(Childs2); + []-> + print_pid(Pid,Node,Mode,App,"<FONT SIZE=2>Start Trace</FONT>")++ + htmlify_prim_child(Childs,Proc_tab,N+1,Node,Mode,App) ++ + htmlify_sec_child(Childs2) + end. + +print_pid(Pid,Node,_Mode,_App,notrace)-> + "<LI><A TARGET=\"proc_data\" STYLE=\"text-decoration:none; color:blue\" HREF=\"./proc_info?name=" ++ urlify_pid(Pid) ++ + "&node="++ Node ++" \" >"++ htmlify_pid(Pid,[]) ++ + "</A>"; + +print_pid([$P,$o,$r,$t|Rest],_Node,_Mode,_App,_TrMode)-> + "<LI>" ++ htmlify_pid([$P,$o,$r,$t|Rest],[]); + +print_pid(Pid,Node,Mode,App,TrMode)-> + "<LI><A TARGET=\"proc_data\" STYLE=\"text-decoration:none; color:blue\" HREF=\"./proc_info?name=" ++ + urlify_pid(Pid) ++ "&node="++ Node ++" \" >"++ + htmlify_pid(Pid,[]) ++ "</A>"++ + "   + <A HREF=\"./trace?app="++App++"&mode="++Mode++ + "&node="++Node++"&proc="++urlify_pid(Pid)++"\"> + "++TrMode++"</A>". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Change the '<' sign and the '>' sign to the html representation %% +%% of the sign %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +htmlify_pid([60|Pid],New)-> + htmlify_pid(Pid,";tl&"++New); +htmlify_pid([139|Pid],New)-> + htmlify_pid(Pid,";tl&"++New); + +htmlify_pid([62|Pid],New)-> + htmlify_pid(Pid,";tg&"++New); +htmlify_pid([155|Pid],New)-> + htmlify_pid(Pid,";tg&"++New); +htmlify_pid([Chr|Pid],New)-> + htmlify_pid(Pid,[Chr|New]); +htmlify_pid([],New)-> + lists:reverse(New). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Change the < and > sign to the representation of the signs in %% +%% the HTTP protocol %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +urlify_pid(Pid) -> + case regexp:first_match(Pid,"[<].*[>]") of + {match,Start,Len}-> + "%3C"++string:substr(Pid,Start+1,Len-2)++"%3E"; + _-> + Pid + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Change the < and > sign from the representation of the signs in %% +%% the HTTP protocol %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +unurlify_pid(Pid)-> + unurlify_pid(Pid,[]). + +unurlify_pid([$%,$3,$C|Rest],New)-> + unurlify_pid(Rest,[60|New]); + +unurlify_pid([$%,$3,$E|Rest],New)-> + unurlify_pid(Rest,[62|New]); +unurlify_pid([Chr|Rest],New)-> + unurlify_pid(Rest,[Chr|New]); + +unurlify_pid([],New)-> + lists:reverse(New). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Make html of the list of primary childs %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +htmlify_prim_child([],_Proc_tab,_N,_Node,_Mode,_App)-> + []; + +htmlify_prim_child(Childs,Proc_tab,N,Node,Mode,App)-> + Fun=fun(Child)-> + htmlify_tree(Child,Proc_tab,N,Node,Mode,App) + end, + "<UL>\n" ++ lists:map(Fun,Childs) ++ "</UL>\n". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Make html of hte list whit sedondary childs, they has no childs %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +htmlify_sec_child([])-> + []; + +htmlify_sec_child(Sec_child_list)-> + Htmlify_child=fun(Pid1)-> + "<LI><FONT COLOR=\"#FF2222\">" ++ Pid1 ++ + "</FONT></LI>\n" + end, + "<UL>" ++ lists:map(Htmlify_child,Sec_child_list) ++ "</UL>\n". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The Private functions that do the job %% +%% To build the the page that shows process data %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The function that creates the collects the various part of %% +%% the side that shows information about a specific process, %% +%% Pid_name should be the list representation of a pid %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +process_body(Args) when length(Args)==2-> + Pid=element(2,lists:nth(1,Args)), + Node=element(2,lists:nth(2,Args)), + "<BODY BGCOLOR=\"#FFFFFF\">" ++ + process_information_table(Pid,Node) ++ "</BODY>"; + +process_body(_)-> + "<BODY BGCOLOR=\"#FFFFFF\">Please dont call this side manually</BODY>". + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Create the table that shows the name of the pid to show extended %% +%% info about %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Get the table that shows the extended info about a process %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +process_information_table(Pid_name,Node)-> + PidID=unurlify_pid(Pid_name), + case catch list_to_pid(PidID) of + Pid when is_pid(Pid) -> + get_process_table(Pid,Node); + _Other -> + io_lib:format("Not a process id ~s",[PidID]) + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Create the table that shoows the extended info about processes %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +get_process_table(Pid,Node_name) when is_list(Node_name)-> + Node=list_to_atom(Node_name), + get_process_table(Pid,Node); + +get_process_table(Pid,Node) when is_atom(Node)-> + case lists:member(Node,[node()|nodes()]) of + true-> + Proc_data=process_info:get_process_data(Pid,Node), + "<TABLE BORDER=1 > + <TR BGCOLOR=\"#8899AA\"><TD COLSPAN=6 ALIGN=\"center\" > + <FONT size=4> Process" ++ + htmlify_pid(pid_to_list(Pid),[]) ++ "</FONT> + </TD></TR>" ++ + start_process_proc_data(Proc_data) ++ + "</TABLE><BR><BR>"; + _ -> + "Please try again the Node dont exists" + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The process information is quite messy tidi it up by creating a %% +%% table that looks like key val %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start_process_proc_data(Proc_data)-> + %%Pic out the special cases the links and the process dict + {Special,Usual}=split_proc_data(Proc_data), + Usual2=append_empty(Usual), + UsualProcData=process_proc_data(Usual2,0), + SpecProcData=process_proc_data(Special), + UsualProcData++SpecProcData. + +append_empty(List) when length(List) rem 2 == 0 -> + List; +append_empty(List)-> + append_empty(lists:append(List,[empty])). + +split_proc_data(Proc_data)-> + Spec=lists:map(fun(Key)-> + case lists:keysearch(Key,1,Proc_data) of + {value,Data}-> + Data; + _ -> + not_included + end + end,[links,dictionary,messages]), + Spec2=clear(Spec,[]), + Usual=lists:filter(fun({Key,_Val})-> + case Key of + messages -> + false; + links -> + false; + dictionary -> + false; + _ -> + true + end + end,Proc_data), + {Spec2,Usual}. + +clear([],New)-> + New; +clear([not_included|Spec],New)-> + clear(Spec,New); +clear([Other|Spec],New)-> + clear(Spec,[Other|New]). + +process_proc_data(Data,3)-> + "</TR>"++process_proc_data(Data,0); +process_proc_data([],_N)-> + []; +process_proc_data(Data,0)-> + "<TR>"++process_proc_data(Data,1); + +process_proc_data([empty|Data],N)-> + "<TD> </TD><TD> </TD> "++process_proc_data(Data,N+1); + +process_proc_data([{current_function,MFA}|Rest],N)-> + "<TD NOWRAP=true><FONT SIZE=3><B>Current function:</B></TD><TD><FONT SIZE=3>"++ + io_lib:format("~p",[MFA]) ++"</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{error_handler,Mod}|Rest],N)-> + "<TD NOWRAP=\"true\"><B><FONT SIZE=3>Error handler:</B></TD><TD><FONT SIZE=3>" + ++ atom_to_list(Mod) ++ "</TD>\n" ++ + process_proc_data(Rest,N+1); + +process_proc_data([{group_leader,Grp}|Rest],N)-> + "<TD NOWRAP=\"true\"><FONT SIZE=3><B>Group leader:</B></TD><TD><FONT SIZE=3>" ++ + htmlify_pid(pid_to_list(Grp),[]) ++ "</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{heap_size,Size}|Rest],N)-> + "<TD NOWRAP=\"true\"><FONT SIZE=3><B>Heap size:</B></TD><TD><FONT SIZE=3>" + ++ integer_to_list(Size) ++ "</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{initial_call,MFA}|Rest],N)-> + "<TD NOWRAP=\"true\"><FONT SIZE=3><B>Initial call:</B></TD><TD><FONT SIZE=3>"++ + io_lib:format("~p",[MFA]) ++"</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{message_queue_len,Size}|Rest],N)-> + "<TD NOWRAP=\"true\"><FONT SIZE=3><B>Message queue length:</B></TD><TD><FONT SIZE=3>" ++ + integer_to_list(Size) ++ "</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{priority,Level}|Rest],N)-> + "<TD><FONT SIZE=3><B>Process priority:</B></TD><TD><FONT SIZE=3>" ++ + atom_to_list(Level) ++ "</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{reductions,Number}|Rest],N)-> + "<TD ><FONT SIZE=3><B>Number of executed reductions:</B></TD> + <TD><FONT SIZE=3>" ++ integer_to_list(Number) ++ "</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{registered_name,Name}|Rest],N)-> + "<TD NOWRAP=\"true\"><FONT SIZE=3><B>Process Name:</B></TD><TD><FONT SIZE=3>" + ++ atom_to_list(Name) ++ "</TD>\n" ++ + process_proc_data(Rest,N+1); + +process_proc_data([{stack_size,Size}|Rest],N)-> + "<TD NOWRAP=\"true\"><FONT SIZE=3><B>Stack size:</B></TD><TD><FONT SIZE=3>" + ++ integer_to_list(Size) ++ "</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{status,Status}|Rest],N)-> + "<TD NOWRAP=\"true\"><FONT SIZE=3><B>Process status:</B></TD><TD><FONT SIZE=3>" + ++ atom_to_list(Status) ++ "</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{trap_exit,Boolean}|Rest],N)-> + "<TD NOWRAP=\"true\" ><FONT SIZE=3><B>Trap Exit:</B></TD><TD><FONT SIZE=3>" + ++ atom_to_list(Boolean) ++ "</TD>\n " ++ + process_proc_data(Rest,N+1); + +process_proc_data([{Key,Val}|Rest],N)-> + "<TD NOWRAP=\"true\" ><FONT SIZE=3><B>" ++ io_lib:write(Key) ++ + "</B></TD><TD><FONT SIZE=3>" ++ io_lib:write(Val) ++ + "</TD>\n " ++ + process_proc_data(Rest,N). + +process_proc_data([])-> + []; +process_proc_data([{links,List_of_pids}|Rest])-> + "<TR><TD NOWRAP=\"true\"><FONT SIZE=3><B>Links:</B></TD><TD COLSPAN=5><FONT SIZE=3>"++ print_links(List_of_pids) ++"</TD></TR>\n " ++ + process_proc_data(Rest); + +process_proc_data([{messages,Queue}|Rest])-> + "<TR><TD NOWRAP=\"true\"><FONT SIZE=3><B>Message Queue:</B></TD><TD COLSPAN=5><FONT SIZE=3>" ++ io_lib:write(Queue) ++ "</TD></TR>\n " ++ + process_proc_data(Rest); + +process_proc_data([{dictionary,Dict}|Rest])-> + "<TR><TD NOWRAP=\"true\"><FONT SIZE=3><B>Process dictionary:</B></TD><TD COLSPAN=5><FONT SIZE=3> </TD></TR>\n " ++ + get_dictionary_data(Dict) ++ + process_proc_data(Rest). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% In the process info there are the links to other processes print %% +%% this pid %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +print_links(Pids)-> + print_links(Pids,[]). + +print_links([],Links)-> + htmlify_pid(Links,[]); + +print_links([Pid],Links) when is_pid(Pid) -> + print_links([],Links ++ pid_to_list(Pid)); + +print_links([Pid],Links) when is_port(Pid) -> + print_links([],Links ++ erlang:port_to_list(Pid)); + +print_links([Pid|Rest],Links) when is_pid(Pid) -> + print_links(Rest,Links ++ pid_to_list(Pid) ++ ", "); + +print_links([Pid|Rest],Links) when is_port(Pid) -> + print_links(Rest,Links ++ erlang:port_to_list(Pid) ++ ", "). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Fix the data in the process dictionary %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +get_dictionary_data([])-> + []; + +get_dictionary_data([{Key,Val}|Dict])-> + FormatedVal=add_space(htmlify_pid(lists:flatten(fix_type(Val)),[])), + "<TR><TD><FONT SIZE=3>" ++ + htmlify_pid(lists:flatten(fix_type(Key)),[]) ++ + "</TD><TD COLSPAN=5><FONT SIZE=3>" ++ + FormatedVal++ "</TD></TR>\n" ++ + get_dictionary_data(Dict). + +add_space(List)-> + add_space(List,0,[]). +add_space([],_Len,New) -> + lists:reverse(New); +add_space([Char|Rest],Len,New)when Len<50 -> + add_space(Rest,Len+1,[Char|New]); + +add_space([$\,|Rest],_Len,New) -> + add_space(Rest,0,[$\ ,$,|New]); + +add_space([Char|Rest],Len,New) -> + add_space(Rest,Len+1,[Char|New]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Interpret the type of the data and make it to a list %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +fix_type(Val) when is_atom(Val) -> + atom_to_list(Val); +fix_type(Val) when is_float(Val) -> + float_to_list(Val); +fix_type(Val) when is_integer(Val) -> + integer_to_list(Val); +fix_type(Val) when is_list(Val) -> + case io_lib:printable_list(Val) of + true-> + case Val of + []-> + io_lib:write(Val); + _-> + Val + end; + _-> + io_lib:write(Val) + end; +fix_type(Val) when is_pid(Val) -> + pid_to_list(Val); +fix_type(Val) when is_port(Val) -> + erlang:port_to_list(Val); +fix_type(Val) when is_tuple(Val) -> + io_lib:write(Val); +fix_type(_Val) -> + []. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The Private functions that send the trace signal to the process %% +%% thats the 4 member of the Arg list %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +send_trace(Args)when length(Args)>=4-> + {_,Proc}=lists:nth(4,Args), + Pid2=unurlify_pid(Proc), + process_info:send_trace(Pid2); + +send_trace(_Args)-> + arg_error. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Private functions that prints the application environment %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +application_env_body(Args)when length(Args)>=2 -> + App=element(2,lists:nth(1,Args)), + Node=element(2,lists:nth(2,Args)), + "<SCRIPT> + function reload_bottom_frame() + {parent.proc_data.location.href=\"/appmon/blank.html\";} + </SCRIPT> + <BODY BGCOLOR=\"#FFFFFF\" onLoad=reload_bottom_frame()>" + ++ application_env_table(App,Node) ++ "</BODY>"; + +application_env_body(_)-> + "<BODY BGCOLOR=\"#FFFFFF\">Please dont call this side manually</BODY>". + +application_env_table(App,Node)-> + case process_info:get_application_keys(list_to_atom(App), + list_to_atom(Node)) of + {ok,List}-> + "<TABLE BORDER=1>" ++ application_env_head(App,Node) ++ + print_key_list(List,[]) ++ "</TABLE>"; + _ -> + "Please try again,something went wrong" + end. + +application_env_head(App,Node)-> + "<TR BGCOLOR=\"#8899AA\"><TD ALIGN=\"center\" COLSPAN=3> + <FONT SIZE=6>" ++ App ++ "@" ++ Node ++ "</FONT>\n + </TD></TR> + <TR><TD COLSPAN=3> </TD></TR> + <TR BGCOLOR=\"#8899AA\"> + <TD><B>Key</B></TD><TD><B>Val/Sec. key</B></TD><TD><B>Sec. Val</B></TD> + </TR>". + +print_key_list([],Result)-> + Result; + +print_key_list([{application,Name}|Rest],Result)-> + print_key_list(Rest,Result ++ print_key("Application name :",Name)); + +print_key_list([{description,Desc}|Rest],Result)-> + print_key_list(Rest,Result ++ print_key("Description :",Desc)); + +print_key_list([{vsn,Ver}|Rest],Result)-> + print_key_list(Rest,Result ++ print_key("Version :",Ver)); + +print_key_list([{id,Id}|Rest],Result)-> + print_key_list(Rest,Result ++ print_key("ID:",fix_type(Id))); + +print_key_list([{modules,Mods}|Rest],Result)-> + print_key_list(Rest,Result ++ print_key("Modules:"," ") ++ + print_secondary_list(Mods,[])); + +print_key_list([{maxP,Max}|Rest],Result)-> + print_key_list(Rest,Result ++ + print_key("Max nr of processes",fix_type(Max))); + +print_key_list([{maxT,Max}|Rest],Result)-> + print_key_list(Rest,Result ++ + print_key("Max running sec:",fix_type(Max))); + +print_key_list([{registered,Names}|Rest],Result)-> + print_key_list(Rest,Result ++ + print_key("Registered names:"," ") ++ + print_secondary_list(Names,[])); + +print_key_list([{applications,Apps}|Rest],Result)-> + print_key_list(Rest,Result ++ print_key("Depends on:"," ") ++ + print_secondary_list(Apps,[])); + +print_key_list([{included_applications,Inc_apps}|Rest],Result)-> + print_key_list(Rest,Result ++ + print_key("Included applications:", + fix_type(Inc_apps))); + +print_key_list([{env,Env}|Rest],Result)-> + print_key_list(Rest,Result ++ + print_key("Environment:",fix_type(Env))); + +print_key_list([{mod,Mod}|Rest],Result)-> + print_key_list(Rest,Result ++ + print_key("Application callback mod:", + fix_type(Mod))); + +print_key_list([{start_phases,Phase_arg}|Rest],Result)-> + print_key_list(Rest,Result ++ + print_key("Application callback mod:", + fix_type(Phase_arg))); + +print_key_list([_|Rest],Result)-> + print_key_list(Rest,Result). + +print_key(Label,Val)-> + "<TR> + <TD><B>" ++ Label ++ "</B></TD><TD>" ++ Val ++ + "</TD><TD> </TD> + </TR>". + +print_key2(Label,Val)-> + "<TR> + <TD> </TD><TD>" ++ Label ++ "</TD><TD>" ++ Val ++ "</TD> + </TR>". + +print_secondary_list([],Result)-> + Result; +print_secondary_list([{Mod,Ver}|Rest],Result) -> + print_secondary_list(Rest,Result ++ + print_key2(fix_type(Mod),fix_type(Ver))); + +print_secondary_list([Mod|Rest],Result) -> + print_secondary_list(Rest,Result ++ + print_key2(fix_type(Mod)," ")). diff --git a/lib/appmon/src/process_info.erl b/lib/appmon/src/process_info.erl new file mode 100644 index 0000000000..e5d44ae50e --- /dev/null +++ b/lib/appmon/src/process_info.erl @@ -0,0 +1,662 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +-module(process_info). +-behavior(gen_server). + +-export([start/0, start_link/0, stop/0]). +-export([is_node/1, get_nodes/0, + get_applications/1, get_application_keys/2, + get_processes/3, get_process_data/2, + send_trace/1]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-record(data, {que=undef, + procs=undef, + links=undef, + links2=undef}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Functions to retrieve information about which application %% +%% at the node %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +start() -> + gen_server:start({local, proc_info}, process_info, [], []). + +start_link() -> + gen_server:start_link({local, proc_info}, process_info, [], []). + +stop() -> + gen_server:call(proc_info, stop, 1000). + +%% is_node(NodeS) -> {bool(), Node, NodeS2} +%% NodeS = NodeS2 = string() +%% Node = node() +is_node(NodeS) -> + Node = list_to_atom(NodeS), + case lists:member(Node, [node()|nodes()]) of + true-> + {true, Node, NodeS}; + false -> + {false, node(), atom_to_list(node())} + end. + +%% get_nodes() -> [node()] +get_nodes() -> + [node()|nodes()]. + +%% get_applications(Node) -> [App] +%% Node = node() +%% App = atom() +%% Returns the list of all applications with a supervision tree (that +%% is, not library applications such as stdlib) at Node. +get_applications(Node) -> + Info = rpc:call(Node, application, info, []), + {value, {running, Apps}} = lists:keysearch(running, 1, Info), + [App || {App, Pid} <- Apps, is_pid(Pid)]. + +%% get_application_keys(App, Node) -> {ok, Keys} | {error, Reason} +%% Node = node() +%% App = atom() +%% Keys = [{Key, Val}] +%% Key = atom() +%% Val = term() +%% Reason = badapp | badrpc +get_application_keys(App, Node) -> + case rpc:call(Node, application, get_all_key, [App]) of + {ok, Keys} -> + {ok, Keys}; + undefined -> + {error, badapp}; + {badrpc, _} -> + {error, badrpc} + end. + +%% get_processes(App, Mode, Node) -> {Tree, Dict} | unknown +%% App = atom() +%% Mode = sup | sup_child | all +%% Node = node() +get_processes(App, Mode, Node) -> + gen_server:call(proc_info, {get_processes, App, Mode, Node}). + +%% get_process_data(Pid, Node) -> ProcData +%% Pid = pid() +%% Node = node() +%% ProcData -- see erlang:process_info/1 +get_process_data(Pid, Node) -> + case rpc:call(Node, erlang, process_info, [Pid]) of + {badrpc, _} -> + [{error,"Please try again"}]; + Res -> + Res + end. + +%% send_trace(PidL) -> void() +send_trace(PidL) -> + gen_server:call(proc_info, {send_trace, PidL}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% gen_server callbacks %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +init([]) -> + {ok, ets:new(procs, [])}. + +handle_call({get_processes, App, Mode, Node}, _From, State) -> + case do_get_processes(App, Mode, Node) of + unknown -> + {reply, unknown, State}; + Tree -> + {reply, {Tree, State}, State} + end; +handle_call({send_trace, PidL}, _From, State) -> + do_send_trace(PidL, State), + {reply, ok, State}; +handle_call(stop, _From, State) -> + {stop, normal, ok, State}. + +handle_cast(_, State) -> + {noreply, State}. + +handle_info(_, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_, State, _) -> + {ok, State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Internal functions %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% do_get_processes(App, Mode, Node) -> Tree | unknown +%% App = atom() +%% Mode = all | sup | sup_childs +%% Node = node() +%% Tree = term() +do_get_processes(App, Mode, Node) -> + case rpc:call(Node, application_controller, get_master, [App]) of + Pid when is_pid(Pid) -> + start_collecting_data(Pid, Mode, Node); + undefined -> + unknown + end. + +%% Initiate the database, get the processes and the links. +%% Then build lists and return them. +start_collecting_data(Pid, Mode, Node) -> + Db = get_database(), + {Db2, Tree} = build_graph({master,Pid}, Db, Pid, Mode, Node), + delete_database(Db2), + Tree. + +get_database() -> + P = ets:new(procs,[]), + L = ets:new(link,[bag]), + L2 = ets:new(link2,[bag]), + Q = queue:new(), + ets:insert(P, {whereis(application_controller), crap}), + ets:insert(P, {whereis(gs), crap}), + #data{que=Q, procs=P, links=L, links2=L2}. + +delete_database(Db) -> + ets:delete(Db#data.procs), + ets:delete(Db#data.links), + ets:delete(Db#data.links2). + +%% The thought is +%% 1. Get the processes that links to Pid. +%% Pid is the application master the first time. +%% 2. Add the processes to the database and clear the list of children +%% from processes which for some resason not should be there. +%% 3. Queue the children, so we later can se if they have any links. +%% 4. Add links to the childrens. +%% 5. When the whole tree is retreived remove the unnecessary processes +%% depending on the mode. +%% 6. Take all links that point to the same pid and sort out +%% the primary and secondary relations. +%% If more than one process links to the same process, the relation +%% between a supervisor and a process is primary. The rest is +%% secondary, there is no different in real world just in logic +%% between a secondary and a primary relation. +%% When all processes in the application is collected, +%% fix secondary links and return the tree. +build_graph(finish, Db, Grp, Mode, Node) -> + Db = fix_links(Db, Grp, Node), + delete_unwanted(Db, Mode, Grp), + Tree = start_tree(Db, Node), + {Db, Tree}; +build_graph(Pid, Db, Grp, Mode, Node) -> + Children = get_children(Pid, Mode, Node), + Children2 = add_and_remove(Children, Pid, Db, Grp, Node), + Q2 = queue_children(Db#data.que, Children2), + add_children(Pid, Db, Children2, 1), + case queue:out(Q2) of + {empty, _}-> + build_graph(finish, Db, Grp, Mode, Node); + {{value,NPid}, Q3}-> + Db2 = Db#data{que=Q3}, + build_graph(NPid,Db2,Grp,Mode,Node) + end. + +%% Collect the processes which the current process has a link to +%% Pid is now the application_master and the application master's +%% child is the application supervisor but in reality there are two +%% application master processes. +%% Fix this by reordering the processes a little. +get_children({master,Pid}, _Mode, Node) when is_pid(Pid) -> + %% Get the master pid + MPid = case application_master:get_child(Pid) of + {Pid1, _App} -> Pid1; + Pid1 -> Pid1 + end, + %% Get the second appplication master process and order them + %% correctly + case rpc:call(Node, erlang, process_info, [MPid,links]) of + {links, [H|T]} -> [H,MPid|T]; + {links, []} -> MPid + end; +get_children({Pid, _Name}, _Mode, Node) when is_pid(Pid), + Node==node(Pid) -> + {links,Links} = rpc:call(Node, erlang, process_info, [Pid,links]), + Links; +get_children(Pid, _Mode, Node) when is_pid(Pid), Node==node(Pid) -> + {links,Links} = rpc:call(Node, erlang, process_info, [Pid,links]), + Links; +get_children(Pid, _Mode, Node) when is_pid(Pid), Node/=node(Pid) -> + []; +get_children(Port, _Mode, _Node) when is_port(Port) -> + []. + +%% Add the links to the database. +%% The first case -- when it is the application master process -- there +%% is only one real child even though there are more links. +add_children({master,Pid}, Db, [Child|_Rest], N) -> + add_child(Pid, Db, Child, N); +add_children(_Pid, _Db, [], _N) -> + ok; +add_children(Pid, Db, [Child|Rest], N) -> + add_child(Pid, Db, Child, N), + add_children(Pid, Db, Rest, N+1). + +add_child(Pid, Db, Child, N) -> + case ets:match_object(Db#data.links, {Pid,Child,'_'}) of + [] -> + ets:insert(Db#data.links, {Pid,Child,N}); + _ -> + ok + end. + +%% Add the list of processes to the queue. +queue_children(Queue, []) -> + Queue; +queue_children(Queue, [H|T]) -> + Q = queue:in(H, Queue), + queue_children(Q, T). + +%% The processess that we already has added to the database are +%% not children to the current process, so we don't need to add them a +%% second time. +remove_used_children([], _Db, New_list) -> + lists:reverse(New_list); +remove_used_children([Child|Rest], Db, New) -> + case ets:lookup(Db#data.procs, Child) of + [] -> + remove_used_children(Rest, Db, [Child|New]); + _ -> + remove_used_children(Rest, Db, New) + end. + +%% Take the list of links and separate it into a list with ports and a +%% list with pids. +separate_ports([], Pids, Ports) -> + {Pids, Ports}; +separate_ports([Child|Rest], Pids, Ports) -> + if + is_port(Child) -> + separate_ports(Rest, Pids, [Child|Ports]); + is_pid(Child) -> + separate_ports(Rest, [Child|Pids], Ports) + end. + +%% Add the current pid to the ets table with processes and clear +%% the list of children from processes that should not be there. +%% In the first case, no children are used so it's not necessary. +add_and_remove(Children, {master,Pid}, Db, _Grp, Node) + when is_pid(Pid), Node==node(Pid) -> + ets:insert(Db#data.procs, {Pid, {master,master}, controller}), + {_Pids,Ports} = separate_ports(Children, [], []), + Ports++Children; +%% This clause is removable when using only link as retrieving mode . +add_and_remove(Children, {Pid,_Name}, Db, Grp, Node) + when is_pid(Pid), Node==node(Pid) -> + ets:insert(Db#data.procs, {Pid, + rpc:call(Node,erlang,process_info, + [Pid,registered_name])}), + {Pids, Ports} = separate_ports(Children, [], []), + Children1 = remove_used_children(Pids, Db, []), + Children2 = remove_others_children(Children1, Grp, Node), + Ports++Children2; +add_and_remove(Children, Pid, Db, Grp, Node) when is_pid(Pid), + Node==node(Pid) -> + ets:insert(Db#data.procs, {Pid, + rpc:call(Node,erlang,process_info, + [Pid,registered_name])}), + {Pids, Ports} = separate_ports(Children, [], []), + Children1 = remove_used_children(Pids, Db, []), + Children2 =remove_others_children(Children1, Grp, Node), + Ports++Children2; +add_and_remove(_Children, Pid, _Db, _Grp, Node) when is_pid(Pid), + Node/=node(Pid) -> + []; +%% Take care of the ports, don't add them to the table with processes. +add_and_remove(_Children, Pid, _Db, _Grp, _Node) when is_port(Pid) -> + []. + +%% Control that the application's group leader is the group leader of +%% Pid +group_leader_check({Pid,_Name}, Grp, Node) -> + group_leader_check(Pid, Grp, Node); +group_leader_check(Pid, Grp, Node) -> + case rpc:call(Node, erlang, process_info, [Pid,group_leader]) of + {_Item, Grp} -> yes; + _ -> no + end. + +%% Take the list of children and remove the ones with anoother group +%% leader. +remove_others_children(Children, Grp, Node) -> + lists:filter(fun(Child) -> + case group_leader_check(Child, Grp, Node) of + yes -> true; + no -> false + end + end, + Children). + +%% Mark the processes in the procs table as either supervisor or worker. +fix_links(Db, Leader, Node) -> + {Sup,_Work} = mark_supervisors_workers(Db, Leader, Node), + ets:match_delete(Db#data.procs, {'_',crap}), + [_Pid|Procs] = ets:tab2list(Db#data.procs), + N_links = get_n_links(Procs, Db#data.links, []), + N_links2 = take_sup_links(Sup, Db#data.links, N_links), + add_shared_links(N_links2, Db#data.links2), + Db. + +%% Add the links that point to the same child to the shared links table +add_shared_links(N_links, Links2) -> + Insert_fun = fun(Link) -> ets:insert(Links2, Link) end, + lists:map(fun(List) -> lists:map(Insert_fun, List) end, N_links). + +%% Take the list of links that point to the same children and remove +%% the ones that are children to supervisors. +%% The first argument is a list of the supervisors. +%% N_links contains a list of list of links that points to the same +%% child. +take_sup_links([], _Db, N_links) -> + N_links; +take_sup_links([H|Supervised], Links_table, N_links) -> + N_list_fun = fun(Link) -> + insert_sup_links(Link, H, Links_table) + end, + N_links2 = lists:map(fun(Link_list) -> + lists:filter(N_list_fun,Link_list) + end, + N_links), + take_sup_links(Supervised, Links_table, N_links2). + +%% Insert the supervised links in the primary links list. +%% This function should be used as a fun to the filter function in +%% take_sup_links/3. +insert_sup_links({From,To,N}, Sup, Links_table) -> + case From of + Sup -> + ets:insert(Links_table, {From,To,N}), + false; + _ -> + true + end. + +%% Get the links which points to the same children. +get_n_links([], _Links, N_link) -> + N_link; +get_n_links([{Pid,_,_}|Procs], Links, N_link) -> + case ets:match_object(Links, {'_',Pid,'_'}) of + L when length(L)>1 -> + ets:match_delete(Links, {'_',Pid,'_'}), + get_n_links(Procs, Links, [L|N_link]); + _L -> + get_n_links(Procs, Links, N_link) + end; +get_n_links([{Pid,_}|Procs], Links, N_link) -> + case ets:match_object(Links, {'_',Pid,'_'}) of + L when length(L)>1 -> + ets:match_delete(Links, {'_',Pid,'_'}), + get_n_links(Procs, Links, [L|N_link]); + _L -> + get_n_links(Procs, Links, N_link) + end. + +%% Mark the processes that are in the supervisor tree as either worker +%% or supervisor. +mark_supervisors_workers(Db, Leader, Node) -> + %% Get the supervisors and workers. + {Sup_list, Worker_list} = get_by_supervisors1(Leader), + %% Update the supervisor pids. + lists:map(fun(Pid) -> + ets:insert(Db#data.procs, + {Pid, + rpc:call(Node, erlang,process_info, + [Pid,registered_name]), + supervisor}) + end, + Sup_list), + %% Update the worker pids. + lists:map(fun(Pid) -> + ets:insert(Db#data.procs, + {Pid, + rpc:call(Node, erlang,process_info, + [Pid,registered_name]), + worker}) + end, + Worker_list), + {lists:reverse(Sup_list), Worker_list}. + +%% The second way to retrieve the applications processes is to go by +%% the supervision tree. +get_by_supervisors1(Leader) -> + case application_master:get_child(Leader) of + {Pid, _Name}-> + get_by_supervisors([{namn,Pid,supervisor,list_of_mods}], + [], []); + Pid -> + get_by_supervisors([{namn,Pid,supervisor,list_of_mods}], + [], []) + end. + +get_by_supervisors([], Sup, Work) -> + {Sup, Work}; +get_by_supervisors([{_,Pid,supervisor,_}|Rest], Sup, Work) + when is_pid(Pid) -> + Children = supervisor:which_children(Pid), + Children2 = lists:append(Children, Rest), + get_by_supervisors(Children2, [Pid|Sup], Work); +get_by_supervisors([{_,Pid,_,_}|Rest], Sup, Work) when is_pid(Pid) -> + get_by_supervisors(Rest, Sup, [Pid|Work]); +get_by_supervisors([_Whatever|Rest], Sup, Work) -> + get_by_supervisors(Rest, Sup, Work). + +%% Use pattern matching to select mode and delete the unneccesary pids +delete_unwanted(Db, sup_child, App_pid) -> + delete_not_in_supervisor_tree(Db), + add_main_link(Db, App_pid), + Db; +delete_unwanted(Db, all, _App_pid) -> + Db; +delete_unwanted(Db, sup, App_pid) -> + delete_workers(Db), + delete_not_in_supervisor_tree(Db), + add_main_link(Db, App_pid), + Db. + +add_main_link(Db, App_pid) -> + case application_master:get_child(App_pid) of + {Pid, _Name} when is_pid(Pid) -> + ets:insert(Db#data.links, {App_pid,Pid,1}); + Pid when is_pid(Pid) -> + ets:insert(Db#data.links, {App_pid,Pid,1}); + _ -> + false + end. + +%% Delete the processes that are in the supervision tree but are +%% workers, and their links. +delete_workers(Db) -> + Pids = ets:match_object(Db#data.procs, {'_','_',worker}), + Pids2 = + lists:map( + fun({Pid,_,_}) -> + %% Remove the unwanted pids from the process table. + ets:match_delete(Db#data.procs, {Pid,'_','_'}), + %% Remove the links to and from the pid. + ets:match_delete(Db#data.links, {Pid,'_','_'}), + ets:match_delete(Db#data.links, {'_',Pid,'_'}), + ets:match_delete(Db#data.links2, {Pid,'_','_'}), + ets:match_delete(Db#data.links2, {'_',Pid,'_'}) + end, + Pids), + Pids2. + +%% Delete the processes that are not in the supervision tree. +delete_not_in_supervisor_tree(Db) -> + Pids = ets:match_object(Db#data.procs,{'_','_'}), + Pids2 = + lists:map( + fun({Pid,_}) -> + %% Remove the unwanted from the process table. + ets:match_delete(Db#data.procs, {Pid,'_'}), + %% Remove the links to and from the pid. + ets:match_delete(Db#data.links, {Pid,'_','_'}), + ets:match_delete(Db#data.links, {'_',Pid,'_'}), + ets:match_delete(Db#data.links2, {Pid,'_','_'}), + ets:match_delete(Db#data.links2, {'_',Pid,'_'}) + end, + Pids), + Pids2. + +%% Start generating the tree. +start_tree(Db, Node) -> + case get_master(Db) of + no -> false; + Pid -> + build_node(Pid, Db, Node) + end. + +%% Build a node and then it runs itself on every child to the current +%% pid. +build_node(Pid, Db, Node) when is_pid(Pid), Node==node(Pid) -> + Sort_fun = fun sort_order/2, + Fix_sec_name_fun = fun(Pid2) -> get_link_name(Pid2, Db) end, + Build_tree_fun = fun({_,Pid1,_}) -> build_node(Pid1,Db,Node) end, + Children = ets:match_object(Db#data.links, {Pid,'_','_'}), + Children1 = lists:sort(Sort_fun, Children), + Sec_children = ets:match_object(Db#data.links2, {Pid,'_','_'}), + {get_name(Pid,Db), + lists:map(Build_tree_fun,Children1), + lists:map(Fix_sec_name_fun,Sec_children)}; +build_node(Pid, _Db, Node) when is_pid(Pid), Node/=node(Pid) -> + {"Runs on another node:"++erlang:pid_to_list(Pid), [], []}; +build_node(Pid, _Db, _Node) when is_port(Pid) -> + {"Port :"++erlang:port_to_list(Pid), [], []}. + +%% Select the name of the pid from the database where we previosly +%% added it. +get_name(Pid, Db) -> + case ets:lookup(Db#data.procs, Pid) of + [{_,{_,master},_}] -> pid_to_list(Pid); + [{_,{_,Name}}] -> atom_to_list(Name)++" : "++pid_to_list(Pid); + [{_,{_,Name},_}] -> atom_to_list(Name)++" : "++pid_to_list(Pid); + _ -> pid_to_list(Pid) + end. + +%% Select the name of the process which we have a link to. +get_link_name({_,Pid,_}, Db) when is_pid(Pid) -> + case ets:lookup(Db#data.procs, Pid) of + [{_,{_,Name}}] -> atom_to_list(Name)++" : "++pid_to_list(Pid); + [{_,{_,Name},_}] -> atom_to_list(Name)++" : "++pid_to_list(Pid); + _ -> pid_to_list(Pid) + end; +get_link_name({_,Port,_}, _Db) when is_port(Port) -> + "Port :"++" : "; +get_link_name(_, _) -> + "". + +%% Sort the links in the order they where added, in ascending order. +sort_order({_,_,N1}, {_,_,N2}) when N1>N2 -> true; +sort_order(_N1, _N2) -> false. + +%% Select the pid of the application master. +get_master(Db) -> + case ets:match_object(Db#data.procs, + {'_',{master,master},controller}) of + [{Pid,_,_}|_Rest] -> Pid; + _ -> no + end. + +%% The main function to handle tracing. +%% Checks if the process is in the table with traced processes. If so, +%% it stops the trace, otherwise it starts the trace. +do_send_trace(PidL, Traced_tab) -> + Pid = list_to_pid(PidL), + Key = get_key(Pid), + case catch ets:lookup(Traced_tab, Key) of + [] -> + trace_process(Pid, Key, true, Traced_tab); + [_Object]-> + trace_process(Pid, Key, false, Traced_tab) + end, + filter_procs(Traced_tab, ets:tab2list(Traced_tab)). + +get_key(Pid) -> + Node = node(Pid), + case rpc:call(Node, erlang, process_info, [Pid,registered_name]) of + [] -> pid_to_list(Pid); + {registered_name, Name} -> + atom_to_list(Name)++" : "++pid_to_list(Pid) + end. + +%% Tries to toggle the trace flag for the process. +trace_process(Pid, Key, On_or_off, Procs_tab) -> + case rpc:call(node(Pid), sys, trace, [Pid,On_or_off,1000]) of + timeout -> + Node = node(Pid), + io:fwrite("timeout node= ~w, Pid= ~w mode= ~w ~n", + [Node, Pid, On_or_off]); + {badrpc, _} -> + Node = node(Pid), + io:fwrite("badrpc node= ~w, Pid= ~w mode= ~w ~n", + [Node, Pid, On_or_off]); + Res -> + Node = node(Pid), + io:fwrite("anymode ~w node= ~w, Pid= ~w mode= ~w ~n", + [Res, Node, Pid,On_or_off]), + case On_or_off of + true -> ets:insert(Procs_tab, {Key,On_or_off}); + false -> ets:delete(Procs_tab, Key) + end + end. + +%% Check if the processes in the ets table with traced processes +%% are alive. If not, remove them. +filter_procs(Tab, Tab_list) -> + lists:foreach(fun({Key,_Val}) -> is_alive(Key, Tab) end, Tab_list). + +is_alive(Key, Tab) -> + case get_pid(Key) of + nopid -> false; + Pid -> is_alive2(Pid, Key, Tab) + end. + +%% Key is either a pid in list form or Pidname:Pid in list form. +get_pid(Key) -> + case catch list_to_pid(string:substr(Key,string:rchr(Key,$<))) of + Pid when is_pid(Pid) -> + Pid; + _ -> + nopid + end. + +is_alive2(Pid, Key, Tab) -> + case catch rpc:call(node(Pid), erlang, is_process_alive, [Pid]) of + true -> true; + false -> + catch ets:delete(Tab, Key), + ok + end. diff --git a/lib/appmon/vsn.mk b/lib/appmon/vsn.mk new file mode 100644 index 0000000000..cbf0a88737 --- /dev/null +++ b/lib/appmon/vsn.mk @@ -0,0 +1,19 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +APPMON_VSN = 2.1.10.2 |